Skip to content

Commit 44e39a6

Browse files
Unai Zorrilla CastroUnai Zorrilla Castro
authored andcommitted
Added IRabbitMQPersisterConnection and more resilient work on rabbitmq event bus
1 parent 101fc58 commit 44e39a6

7 files changed

Lines changed: 295 additions & 83 deletions

File tree

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
using Microsoft.Extensions.Logging;
2+
using Polly;
3+
using Polly.Retry;
4+
using RabbitMQ.Client;
5+
using RabbitMQ.Client.Events;
6+
using RabbitMQ.Client.Exceptions;
7+
using System;
8+
using System.IO;
9+
using System.Net.Sockets;
10+
11+
namespace Microsoft.eShopOnContainers.BuildingBlocks.EventBusRabbitMQ
12+
{
13+
public class DefaultRabbitMQPersisterConnection
14+
: IRabbitMQPersisterConnection
15+
{
16+
private readonly IConnectionFactory _connectionFactory;
17+
private readonly ILogger<DefaultRabbitMQPersisterConnection> _logger;
18+
19+
IConnection _connection;
20+
bool _disposed;
21+
22+
object sync_root = new object();
23+
24+
public DefaultRabbitMQPersisterConnection(IConnectionFactory connectionFactory,ILogger<DefaultRabbitMQPersisterConnection> logger)
25+
{
26+
_connectionFactory = connectionFactory ?? throw new ArgumentNullException(nameof(connectionFactory));
27+
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
28+
}
29+
30+
public bool IsConnected
31+
{
32+
get
33+
{
34+
return _connection != null && _connection.IsOpen && !_disposed;
35+
}
36+
}
37+
38+
public IModel CreateModel()
39+
{
40+
if (!IsConnected)
41+
{
42+
throw new InvalidOperationException("No RabbitMQ connections are available to perform this action");
43+
}
44+
45+
return _connection.CreateModel();
46+
}
47+
48+
public void Dispose()
49+
{
50+
if (_disposed) return;
51+
52+
_disposed = true;
53+
54+
try
55+
{
56+
_connection.Dispose();
57+
}
58+
catch (IOException ex)
59+
{
60+
_logger.LogCritical(ex.ToString());
61+
}
62+
}
63+
64+
public bool TryConnect()
65+
{
66+
_logger.LogInformation("RabbitMQ Client is trying to connect");
67+
68+
lock (sync_root)
69+
{
70+
var policy = RetryPolicy.Handle<SocketException>()
71+
.Or<BrokerUnreachableException>()
72+
.WaitAndRetry(5, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (ex, time) =>
73+
{
74+
_logger.LogWarning(ex.ToString());
75+
}
76+
);
77+
78+
policy.Execute(() =>
79+
{
80+
_connection = _connectionFactory
81+
.CreateConnection();
82+
});
83+
84+
if (IsConnected)
85+
{
86+
_connection.ConnectionShutdown += OnConnectionShutdown;
87+
_connection.CallbackException += OnCallbackException;
88+
_connection.ConnectionBlocked += OnConnectionBlocked;
89+
90+
_logger.LogInformation($"RabbitMQ persister connection acquire a connection {_connection.Endpoint.HostName} and is subscribed to failure events");
91+
92+
return true;
93+
}
94+
else
95+
{
96+
_logger.LogCritical("FATAL ERROR: RabbitMQ connections can't be created and opened");
97+
98+
return false;
99+
}
100+
}
101+
}
102+
103+
private void OnConnectionBlocked(object sender, ConnectionBlockedEventArgs e)
104+
{
105+
if (_disposed) return;
106+
107+
_logger.LogWarning("A RabbitMQ connection is shutdown. Trying to re-connect...");
108+
109+
TryConnect();
110+
}
111+
112+
void OnCallbackException(object sender, CallbackExceptionEventArgs e)
113+
{
114+
if (_disposed) return;
115+
116+
_logger.LogWarning("A RabbitMQ connection throw exception. Trying to re-connect...");
117+
118+
TryConnect();
119+
}
120+
121+
void OnConnectionShutdown(object sender, ShutdownEventArgs reason)
122+
{
123+
if (_disposed) return;
124+
125+
_logger.LogWarning("A RabbitMQ connection is on shutdown. Trying to re-connect...");
126+
127+
TryConnect();
128+
}
129+
}
130+
}

0 commit comments

Comments
 (0)