From 597a23cb42176934d4c925fdfc35f0945d065b6e Mon Sep 17 00:00:00 2001 From: Blake Niemyjski Date: Fri, 22 Nov 2024 12:05:38 -0600 Subject: [PATCH] Upgrade to RabbitMQ 7 --- Foundatio.RabbitMQ.sln | 1 + build/Dockerfile | 4 +- build/common.props | 2 +- ...abbitmq_delayed_message_exchange-3.10.0.ez | Bin 35226 -> 0 bytes ...rabbitmq_delayed_message_exchange-4.0.2.ez | Bin 0 -> 42112 bytes docker-compose.yml | 2 +- .../Extensions/TaskExtensions.cs | 6 + .../Foundatio.RabbitMQ.csproj | 2 +- .../Messaging/RabbitMQMessageBus.cs | 238 +++++++++++------- 9 files changed, 158 insertions(+), 97 deletions(-) delete mode 100644 build/rabbitmq_delayed_message_exchange-3.10.0.ez create mode 100644 build/rabbitmq_delayed_message_exchange-4.0.2.ez diff --git a/Foundatio.RabbitMQ.sln b/Foundatio.RabbitMQ.sln index 7b1d511..6d38288 100644 --- a/Foundatio.RabbitMQ.sln +++ b/Foundatio.RabbitMQ.sln @@ -12,6 +12,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution README.md = README.md docker-compose.yml = docker-compose.yml tests\Directory.Build.props = tests\Directory.Build.props + build\Dockerfile = build\Dockerfile EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Foundatio.RabbitMQ", "src\Foundatio.RabbitMQ\Foundatio.RabbitMQ.csproj", "{EAE3607D-73A1-4D02-BDAA-24A37DDA15CB}" diff --git a/build/Dockerfile b/build/Dockerfile index f1d3113..e7557aa 100644 --- a/build/Dockerfile +++ b/build/Dockerfile @@ -1,4 +1,4 @@ -FROM rabbitmq:3.10-management +FROM rabbitmq:4.0.3-management -COPY rabbitmq_delayed_message_exchange-3.10.0.ez /opt/rabbitmq/plugins +COPY rabbitmq_delayed_message_exchange-4.0.2.ez /opt/rabbitmq/plugins RUN rabbitmq-plugins enable rabbitmq_delayed_message_exchange diff --git a/build/common.props b/build/common.props index dbc0634..59ea214 100644 --- a/build/common.props +++ b/build/common.props @@ -1,7 +1,7 @@ - netstandard2.0 + netstandard2.1 Foundatio Pluggable foundation blocks for building distributed apps. https://github.com/FoundatioFx/Foundatio.RabbitMQ diff --git a/build/rabbitmq_delayed_message_exchange-3.10.0.ez b/build/rabbitmq_delayed_message_exchange-3.10.0.ez deleted file mode 100644 index 4f7d6a7aa18fd0c8a13f3114b21d3501411191d5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35226 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 literal 0 HcmV?d00001 diff --git a/docker-compose.yml b/docker-compose.yml index ae8179c..a259cf2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,6 @@ services: rabbitmq: - image: rabbitmq:3.10-management + image: rabbitmq:4.0.3-management ports: - "5672:5672" - "8080:15672" # management ui - login with guest:guest diff --git a/src/Foundatio.RabbitMQ/Extensions/TaskExtensions.cs b/src/Foundatio.RabbitMQ/Extensions/TaskExtensions.cs index f0fd963..deba7e2 100644 --- a/src/Foundatio.RabbitMQ/Extensions/TaskExtensions.cs +++ b/src/Foundatio.RabbitMQ/Extensions/TaskExtensions.cs @@ -25,4 +25,10 @@ public static ConfiguredTaskAwaitable AnyContext(this Awaitabl { return task.ConfigureAwait(continueOnCapturedContext: false); } + + [DebuggerStepThrough] + public static ConfiguredValueTaskAwaitable AnyContext(this ValueTask task) + { + return task.ConfigureAwait(continueOnCapturedContext: false); + } } diff --git a/src/Foundatio.RabbitMQ/Foundatio.RabbitMQ.csproj b/src/Foundatio.RabbitMQ/Foundatio.RabbitMQ.csproj index 0d4c794..06e5cab 100644 --- a/src/Foundatio.RabbitMQ/Foundatio.RabbitMQ.csproj +++ b/src/Foundatio.RabbitMQ/Foundatio.RabbitMQ.csproj @@ -1,6 +1,6 @@ - + diff --git a/src/Foundatio.RabbitMQ/Messaging/RabbitMQMessageBus.cs b/src/Foundatio.RabbitMQ/Messaging/RabbitMQMessageBus.cs index e17a0df..a2b1349 100644 --- a/src/Foundatio.RabbitMQ/Messaging/RabbitMQMessageBus.cs +++ b/src/Foundatio.RabbitMQ/Messaging/RabbitMQMessageBus.cs @@ -13,15 +13,16 @@ namespace Foundatio.Messaging; -public class RabbitMQMessageBus : MessageBusBase +public class RabbitMQMessageBus : MessageBusBase, IAsyncDisposable { private readonly AsyncLock _lock = new(); private readonly ConnectionFactory _factory; private IConnection _publisherConnection; private IConnection _subscriberConnection; - private IModel _publisherModel; - private IModel _subscriberModel; + private IChannel _publisherChannel; + private IChannel _subscriberChannel; private bool? _delayedExchangePluginEnabled; + private bool _isDisposed; public RabbitMQMessageBus(RabbitMQMessageBusOptions options) : base(options) { @@ -32,12 +33,11 @@ public RabbitMQMessageBus(RabbitMQMessageBusOptions options) : base(options) // in case the server is restarted or there has been any network failures // Topology ( queues, exchanges, bindings and consumers) recovery "TopologyRecoveryEnabled" is already enabled // by default so no need to initialize it. NetworkRecoveryInterval is also by default set to 5 seconds. - // it can always be fine tuned if needed. + // it can always be fine-tuned if needed. _factory = new ConnectionFactory { Uri = new Uri(options.ConnectionString), - AutomaticRecoveryEnabled = true, - DispatchConsumersAsync = true + AutomaticRecoveryEnabled = true }; } @@ -48,58 +48,54 @@ protected override Task RemoveTopicSubscriptionAsync() { if (_logger.IsEnabled(LogLevel.Trace)) _logger.LogTrace("RemoveTopicSubscriptionAsync"); - CloseSubscriberConnection(); - return Task.CompletedTask; + + return CloseSubscriberConnectionAsync(); } protected override async Task EnsureTopicSubscriptionAsync(CancellationToken cancellationToken) { - if (_subscriberModel != null) + if (_subscriberChannel != null) return; await EnsureTopicCreatedAsync(cancellationToken).AnyContext(); using (await _lock.LockAsync().AnyContext()) { - if (_subscriberModel != null) + if (_subscriberChannel != null) return; - _subscriberConnection = CreateConnection(); - _subscriberModel = _subscriberConnection.CreateModel(); + _subscriberConnection = await CreateConnectionAsync().AnyContext(); + _subscriberChannel = await _subscriberConnection.CreateChannelAsync(cancellationToken: cancellationToken).AnyContext(); - // If InitPublisher is called first, then we will never come in this if clause. - if (!CreateDelayedExchange(_subscriberModel)) + // If InitPublisher is called first, then we will never come in this if-clause. + if (!await CreateDelayedExchangeAsync(_subscriberChannel).AnyContext()) { - _subscriberModel.Close(); - _subscriberModel.Abort(); - _subscriberModel.Dispose(); - - _subscriberConnection.Close(); - _subscriberConnection.Dispose(); + await _subscriberChannel.DisposeAsync().AnyContext(); + await _subscriberConnection.DisposeAsync().AnyContext(); - _subscriberConnection = CreateConnection(); - _subscriberModel = _subscriberConnection.CreateModel(); - CreateRegularExchange(_subscriberModel); + _subscriberConnection = await CreateConnectionAsync().AnyContext(); + _subscriberChannel = await _subscriberConnection.CreateChannelAsync(cancellationToken: cancellationToken).AnyContext(); + await CreateRegularExchangeAsync(_subscriberChannel).AnyContext(); } - string queueName = CreateQueue(_subscriberModel); - var consumer = new AsyncEventingBasicConsumer(_subscriberModel); - consumer.Received += OnMessage; - consumer.Shutdown += OnConsumerShutdown; + string queueName = await CreateQueueAsync(_subscriberChannel).AnyContext(); + var consumer = new AsyncEventingBasicConsumer(_subscriberChannel); + consumer.ReceivedAsync += OnMessageAsync; + consumer.ShutdownAsync += OnConsumerShutdownAsync; - _subscriberModel.BasicConsume(queueName, _options.AcknowledgementStrategy == AcknowledgementStrategy.FireAndForget, consumer); + await _subscriberChannel.BasicConsumeAsync(queueName, _options.AcknowledgementStrategy == AcknowledgementStrategy.FireAndForget, consumer, cancellationToken: cancellationToken).AnyContext(); if (_logger.IsEnabled(LogLevel.Trace)) - _logger.LogTrace("The unique channel number for the subscriber is : {ChannelNumber}", _subscriberModel.ChannelNumber); + _logger.LogTrace("The unique channel number for the subscriber is : {ChannelNumber}", _subscriberChannel.ChannelNumber); } } - private Task OnConsumerShutdown(object sender, ShutdownEventArgs e) + private Task OnConsumerShutdownAsync(object sender, ShutdownEventArgs e) { _logger.LogInformation("Consumer shutdown. Reply Code: {ReplyCode} Reason: {ReplyText}", e.ReplyCode, e.ReplyText); return Task.CompletedTask; } - private async Task OnMessage(object sender, BasicDeliverEventArgs envelope) + private async Task OnMessageAsync(object sender, BasicDeliverEventArgs envelope) { if (_logger.IsEnabled(LogLevel.Trace)) _logger.LogTrace("OnMessageAsync({MessageId})", envelope.BasicProperties?.MessageId); @@ -110,7 +106,7 @@ private async Task OnMessage(object sender, BasicDeliverEventArgs envelope) _logger.LogTrace("No subscribers ({MessageId})", envelope.BasicProperties?.MessageId); if (_options.AcknowledgementStrategy == AcknowledgementStrategy.Automatic) - _subscriberModel.BasicReject(envelope.DeliveryTag, true); + await _subscriberChannel.BasicRejectAsync(envelope.DeliveryTag, true).AnyContext(); return; } @@ -121,14 +117,14 @@ private async Task OnMessage(object sender, BasicDeliverEventArgs envelope) await SendMessageToSubscribersAsync(message).AnyContext(); if (_options.AcknowledgementStrategy == AcknowledgementStrategy.Automatic) - _subscriberModel.BasicAck(envelope.DeliveryTag, false); + await _subscriberChannel.BasicAckAsync(envelope.DeliveryTag, false).AnyContext(); } catch (Exception ex) { _logger.LogError(ex, "Error handling message ({MessageId}): {Message}", envelope.BasicProperties?.MessageId, ex.Message); if (_options.AcknowledgementStrategy == AcknowledgementStrategy.Automatic) - _subscriberModel.BasicReject(envelope.DeliveryTag, true); + await _subscriberChannel.BasicRejectAsync(envelope.DeliveryTag, true).AnyContext(); } } @@ -161,43 +157,39 @@ protected virtual IMessage ConvertToMessage(BasicDeliverEventArgs envelope) protected override async Task EnsureTopicCreatedAsync(CancellationToken cancellationToken) { - if (_publisherModel != null) + if (_publisherChannel != null) return; using (await _lock.LockAsync().AnyContext()) { - if (_publisherModel != null) + if (_publisherChannel != null) return; // Create the client connection, channel, declares the exchange, queue and binds // the exchange with the publisher queue. It requires the name of our exchange, exchange type, durability and auto-delete. - // For now we are using same autoDelete for both exchange and queue ( it will survive a server restart ) - _publisherConnection = CreateConnection(); - _publisherModel = _publisherConnection.CreateModel(); + // For now, we are using same autoDelete for both exchange and queue ( it will survive a server restart ) + _publisherConnection = await CreateConnectionAsync().AnyContext(); + _publisherChannel = await _publisherConnection.CreateChannelAsync(cancellationToken: cancellationToken).AnyContext(); // We first attempt to create "x-delayed-type". For this plugin should be installed. - // However, we plugin is not installed this will throw an exception. In that case + // However, we plug in is not installed this will throw an exception. In that case // we attempt to create regular exchange. If regular exchange also throws and exception // then trouble shoot the problem. - if (!CreateDelayedExchange(_publisherModel)) + if (!await CreateDelayedExchangeAsync(_publisherChannel).AnyContext()) { // if the initial exchange creation was not successful then we must close the previous connection // and establish the new client connection and model otherwise you will keep receiving failure in creation // of the regular exchange too. - _publisherModel.Close(); - _publisherModel.Abort(); - _publisherModel.Dispose(); + await _publisherChannel.DisposeAsync().AnyContext(); + await _publisherConnection.DisposeAsync().AnyContext(); - _publisherConnection.Close(); - _publisherConnection.Dispose(); - - _publisherConnection = CreateConnection(); - _publisherModel = _publisherConnection.CreateModel(); - CreateRegularExchange(_publisherModel); + _publisherConnection = await CreateConnectionAsync().AnyContext(); + _publisherChannel = await _publisherConnection.CreateChannelAsync(cancellationToken: cancellationToken).AnyContext(); + await CreateRegularExchangeAsync(_publisherChannel).AnyContext(); } if (_logger.IsEnabled(LogLevel.Trace)) - _logger.LogTrace("The unique channel number for the publisher is : {ChannelNumber}", _publisherModel.ChannelNumber); + _logger.LogTrace("The unique channel number for the publisher is : {ChannelNumber}", _publisherChannel.ChannelNumber); } } @@ -212,7 +204,7 @@ protected override async Task EnsureTopicCreatedAsync(CancellationToken cancella /// The rule of thumb is: avoid sharing channels across threads. /// Publishers in your application that publish from separate threads should use their own channels. /// The same is a good idea for consumers. - protected override Task PublishImplAsync(string messageType, object message, MessageOptions options, CancellationToken cancellationToken) + protected override async Task PublishImplAsync(string messageType, object message, MessageOptions options, CancellationToken cancellationToken) { byte[] data = SerializeMessageBody(messageType, message); @@ -223,13 +215,16 @@ protected override Task PublishImplAsync(string messageType, object message, Mes if (_logger.IsEnabled(LogLevel.Trace)) _logger.LogTrace("Schedule delayed message: {MessageType} ({Delay}ms)", messageType, options.DeliveryDelay.Value.TotalMilliseconds); - return AddDelayedMessageAsync(mappedType, message, options.DeliveryDelay.Value); + await AddDelayedMessageAsync(mappedType, message, options.DeliveryDelay.Value).AnyContext(); + return; } - var basicProperties = _publisherModel.CreateBasicProperties(); - basicProperties.MessageId = options.UniqueId ?? Guid.NewGuid().ToString("N"); - basicProperties.CorrelationId = options.CorrelationId; - basicProperties.Type = messageType; + var basicProperties = new BasicProperties + { + MessageId = options.UniqueId ?? Guid.NewGuid().ToString("N"), + CorrelationId = options.CorrelationId, + Type = messageType, + }; if (_options.IsDurable) basicProperties.Persistent = true; @@ -246,7 +241,7 @@ protected override Task PublishImplAsync(string messageType, object message, Mes // RabbitMQ only supports delayed messages with a third party plugin called "rabbitmq_delayed_message_exchange" if (_delayedExchangePluginEnabled.Value && options.DeliveryDelay.HasValue && options.DeliveryDelay.Value > TimeSpan.Zero) { - // Its necessary to typecast long to int because RabbitMQ on the consumer side is reading the + // It's necessary to typecast long to int because RabbitMQ on the consumer side is reading the // data back as signed (using BinaryReader#ReadInt64). You will see the value to be negative // and the data will be delivered immediately. basicProperties.Headers = new Dictionary { { "x-delay", Convert.ToInt32(options.DeliveryDelay.Value.TotalMilliseconds) } }; @@ -258,30 +253,27 @@ protected override Task PublishImplAsync(string messageType, object message, Mes if (_logger.IsEnabled(LogLevel.Trace)) _logger.LogTrace("Message publish type {MessageType} {MessageId}", messageType, basicProperties.MessageId); } - // The publication occurs with mandatory=false - lock (_publisherModel) - _publisherModel.BasicPublish(_options.Topic, String.Empty, basicProperties, data); + using (await _lock.LockAsync().AnyContext()) + await _publisherChannel.BasicPublishAsync(_options.Topic, String.Empty, mandatory: false, basicProperties, data, cancellationToken: cancellationToken).AnyContext(); if (_logger.IsEnabled(LogLevel.Trace)) _logger.LogTrace("Done publishing type {MessageType} {MessageId}", messageType, basicProperties.MessageId); - - return Task.CompletedTask; } ///

/// Connect to a broker - RabbitMQ /// /// - private IConnection CreateConnection() + private Task CreateConnectionAsync() { - return _factory.CreateConnection(); + return _factory.CreateConnectionAsync(); } /// /// Attempts to create the delayed exchange. /// - /// + /// /// true if the delayed exchange was successfully declared. Which means plugin was installed. - private bool CreateDelayedExchange(IModel model) + private async Task CreateDelayedExchangeAsync(IChannel channel) { bool success = true; if (_delayedExchangePluginEnabled.HasValue) @@ -293,24 +285,21 @@ private bool CreateDelayedExchange(IModel model) // Disclaimer : https://github.com/rabbitmq/rabbitmq-delayed-message-exchange/ // Please read the *Performance Impact* of the delayed exchange type. var args = new Dictionary { { "x-delayed-type", ExchangeType.Fanout } }; - model.ExchangeDeclare(_options.Topic, "x-delayed-message", _options.IsDurable, false, args); + await channel.ExchangeDeclareAsync(_options.Topic, "x-delayed-message", _options.IsDurable, false, args).AnyContext(); } catch (OperationInterruptedException ex) { - if (ex.ShutdownReason.ReplyCode == 503) - { - if (_logger.IsEnabled(LogLevel.Information)) _logger.LogInformation(ex, "Not able to create x-delayed-type exchange"); - success = false; - } + _logger.LogInformation(ex, "Unable to create x-delayed-type exchange: {Message}", ex.Message); + success = false; } _delayedExchangePluginEnabled = success; return _delayedExchangePluginEnabled.Value; } - private void CreateRegularExchange(IModel model) + private Task CreateRegularExchangeAsync(IChannel channel) { - model.ExchangeDeclare(_options.Topic, ExchangeType.Fanout, _options.IsDurable, false, null); + return channel.ExchangeDeclareAsync(_options.Topic, ExchangeType.Fanout, _options.IsDurable, false); } /// @@ -319,17 +308,17 @@ private void CreateRegularExchange(IModel model) /// receiver attached which will process the message. We’ll initiate a dedicated message /// exchange and not use the default one. Note that a queue can be dedicated to one or more routing keys. /// - /// channel - private string CreateQueue(IModel model) + /// channel + private async Task CreateQueueAsync(IChannel channel) { - // Setup the queue where the messages will reside - it requires the queue name and durability. + // Set up the queue where the messages will reside - it requires the queue name and durability. // Durable (the queue will survive a broker restart) // Arguments (some brokers use it to implement additional features like message TTL) - var result = model.QueueDeclare(_options.SubscriptionQueueName, _options.IsDurable, _options.IsSubscriptionQueueExclusive, _options.SubscriptionQueueAutoDelete, _options.Arguments); + var result = await channel.QueueDeclareAsync(_options.SubscriptionQueueName, _options.IsDurable, _options.IsSubscriptionQueueExclusive, _options.SubscriptionQueueAutoDelete, _options.Arguments).AnyContext(); string queueName = result.QueueName; // bind the queue with the exchange. - model.QueueBind(queueName, _options.Topic, ""); + await channel.QueueBindAsync(queueName, _options.Topic, "").AnyContext(); return queueName; } @@ -338,11 +327,34 @@ public override void Dispose() { base.Dispose(); + if (_isDisposed) + return; + + _isDisposed = true; + if (_factory != null) _factory.AutomaticRecoveryEnabled = false; ClosePublisherConnection(); CloseSubscriberConnection(); + GC.SuppressFinalize(this); + } + + public async ValueTask DisposeAsync() + { + base.Dispose(); + + if (_isDisposed) + return; + + _isDisposed = true; + + if (_factory != null) + _factory.AutomaticRecoveryEnabled = false; + + await ClosePublisherConnectionAsync().AnyContext(); + await CloseSubscriberConnectionAsync().AnyContext(); + GC.SuppressFinalize(this); } private void ClosePublisherConnection() @@ -355,23 +367,44 @@ private void ClosePublisherConnection() if (_logger.IsEnabled(LogLevel.Trace)) _logger.LogTrace("ClosePublisherConnection"); - if (_publisherModel != null) + if (_publisherChannel != null) { - _publisherModel.Close(); - _publisherModel.Abort(); - _publisherModel.Dispose(); - _publisherModel = null; + _publisherChannel.Dispose(); + _publisherChannel = null; } if (_publisherConnection != null) { - _publisherConnection.Close(); _publisherConnection.Dispose(); _publisherConnection = null; } } } + private async Task ClosePublisherConnectionAsync() + { + if (_publisherConnection == null) + return; + + using (await _lock.LockAsync().AnyContext()) + { + if (_logger.IsEnabled(LogLevel.Trace)) + _logger.LogTrace("ClosePublisherConnectionAsync"); + + if (_publisherChannel != null) + { + _publisherChannel.DisposeAsync().AnyContext(); + _publisherChannel = null; + } + + if (_publisherConnection != null) + { + await _publisherConnection.DisposeAsync().AnyContext(); + _publisherConnection = null; + } + } + } + private void CloseSubscriberConnection() { if (_subscriberConnection == null) @@ -382,20 +415,41 @@ private void CloseSubscriberConnection() if (_logger.IsEnabled(LogLevel.Trace)) _logger.LogTrace("CloseSubscriberConnection"); - if (_subscriberModel != null) + if (_subscriberChannel != null) { - _subscriberModel.Close(); - _subscriberModel.Abort(); - _subscriberModel.Dispose(); - _subscriberModel = null; + _subscriberChannel.Dispose(); + _subscriberChannel = null; } if (_subscriberConnection != null) { - _subscriberConnection.Close(); _subscriberConnection.Dispose(); _subscriberConnection = null; } } } + + private async Task CloseSubscriberConnectionAsync() + { + if (_subscriberConnection == null) + return; + + using (await _lock.LockAsync().AnyContext()) + { + if (_logger.IsEnabled(LogLevel.Trace)) + _logger.LogTrace("CloseSubscriberConnectionAsync"); + + if (_subscriberChannel != null) + { + await _subscriberChannel.DisposeAsync().AnyContext(); + _subscriberChannel = null; + } + + if (_subscriberConnection != null) + { + await _subscriberConnection.DisposeAsync().AnyContext(); + _subscriberConnection = null; + } + } + } }