Mark van Renswoude
2e2a77a7ae
- Consume calls still in the TapetiClient task queue while it is reconnecting would not be cancelled, but new calls were added as well after the reconnect - Unrelated but useful: added LocalPort and Disconnect event to logging
173 lines
4.8 KiB
C#
173 lines
4.8 KiB
C#
using System;
|
|
using System.Threading.Tasks;
|
|
using Tapeti.Config;
|
|
using Tapeti.Connection;
|
|
|
|
// ReSharper disable UnusedMember.Global
|
|
|
|
// TODO more separation from the actual worker / RabbitMQ Client for unit testing purposes
|
|
|
|
namespace Tapeti
|
|
{
|
|
/// <inheritdoc />
|
|
/// <summary>
|
|
/// Creates a connection to RabbitMQ based on the provided Tapeti config.
|
|
/// </summary>
|
|
public class TapetiConnection : IConnection
|
|
{
|
|
private readonly ITapetiConfig config;
|
|
|
|
/// <summary>
|
|
/// Specifies the hostname and credentials to use when connecting to RabbitMQ.
|
|
/// Defaults to guest on localhost.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// This property must be set before first subscribing or publishing, otherwise it
|
|
/// will use the default connection parameters.
|
|
/// </remarks>
|
|
public TapetiConnectionParams Params { get; set; }
|
|
|
|
private readonly Lazy<ITapetiClient> client;
|
|
private TapetiSubscriber subscriber;
|
|
|
|
/// <summary>
|
|
/// Creates a new instance of a TapetiConnection and registers a default IPublisher
|
|
/// in the IoC container as provided in the config.
|
|
/// </summary>
|
|
/// <param name="config"></param>
|
|
public TapetiConnection(ITapetiConfig config)
|
|
{
|
|
this.config = config;
|
|
(config.DependencyResolver as IDependencyContainer)?.RegisterDefault(GetPublisher);
|
|
|
|
client = new Lazy<ITapetiClient>(() => new TapetiClient(config, Params ?? new TapetiConnectionParams())
|
|
{
|
|
ConnectionEventListener = new ConnectionEventListener(this)
|
|
});
|
|
}
|
|
|
|
/// <inheritdoc />
|
|
public event ConnectedEventHandler Connected;
|
|
|
|
/// <inheritdoc />
|
|
public event DisconnectedEventHandler Disconnected;
|
|
|
|
/// <inheritdoc />
|
|
public event ConnectedEventHandler Reconnected;
|
|
|
|
|
|
/// <inheritdoc />
|
|
public async Task<ISubscriber> Subscribe(bool startConsuming = true)
|
|
{
|
|
if (subscriber == null)
|
|
{
|
|
subscriber = new TapetiSubscriber(() => client.Value, config);
|
|
await subscriber.ApplyBindings();
|
|
}
|
|
|
|
if (startConsuming)
|
|
await subscriber.Resume();
|
|
|
|
return subscriber;
|
|
}
|
|
|
|
|
|
/// <inheritdoc />
|
|
public ISubscriber SubscribeSync(bool startConsuming = true)
|
|
{
|
|
return Subscribe(startConsuming).Result;
|
|
}
|
|
|
|
|
|
/// <inheritdoc />
|
|
public IPublisher GetPublisher()
|
|
{
|
|
return new TapetiPublisher(config, () => client.Value);
|
|
}
|
|
|
|
|
|
/// <inheritdoc />
|
|
public async Task Close()
|
|
{
|
|
if (client.IsValueCreated)
|
|
await client.Value.Close();
|
|
}
|
|
|
|
|
|
/// <inheritdoc />
|
|
public void Dispose()
|
|
{
|
|
Close().Wait();
|
|
|
|
subscriber?.Dispose();
|
|
}
|
|
|
|
|
|
private class ConnectionEventListener: IConnectionEventListener
|
|
{
|
|
private readonly TapetiConnection owner;
|
|
|
|
internal ConnectionEventListener(TapetiConnection owner)
|
|
{
|
|
this.owner = owner;
|
|
}
|
|
|
|
public void Connected(ConnectedEventArgs e)
|
|
{
|
|
owner.OnConnected(e);
|
|
}
|
|
|
|
public void Disconnected(DisconnectedEventArgs e)
|
|
{
|
|
owner.OnDisconnected(e);
|
|
}
|
|
|
|
public void Reconnected(ConnectedEventArgs e)
|
|
{
|
|
owner.OnReconnected(e);
|
|
}
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Called when a connection to RabbitMQ has been established.
|
|
/// </summary>
|
|
protected virtual void OnConnected(ConnectedEventArgs e)
|
|
{
|
|
var connectedEvent = Connected;
|
|
if (connectedEvent == null)
|
|
return;
|
|
|
|
Task.Run(() => connectedEvent.Invoke(this, e));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when the connection to RabbitMQ has been lost.
|
|
/// </summary>
|
|
protected virtual void OnReconnected(ConnectedEventArgs e)
|
|
{
|
|
var reconnectedEvent = Reconnected;
|
|
if (reconnectedEvent == null && subscriber == null)
|
|
return;
|
|
|
|
subscriber?.Reconnect();
|
|
|
|
Task.Run(() => reconnectedEvent?.Invoke(this, e));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Called when the connection to RabbitMQ has been recovered after an unexpected disconnect.
|
|
/// </summary>
|
|
protected virtual void OnDisconnected(DisconnectedEventArgs e)
|
|
{
|
|
var disconnectedEvent = Disconnected;
|
|
if (disconnectedEvent == null)
|
|
return;
|
|
|
|
subscriber?.Disconnect();
|
|
|
|
Task.Run(() => disconnectedEvent.Invoke(this, e));
|
|
}
|
|
}
|
|
}
|