diff --git a/Sources/Contour/Contour.csproj b/Sources/Contour/Contour.csproj
index bc10bdd..d00b97e 100644
--- a/Sources/Contour/Contour.csproj
+++ b/Sources/Contour/Contour.csproj
@@ -14,7 +14,7 @@
-
+
diff --git a/Sources/Contour/Transport/RabbitMQ/BusConfigurationEx.cs b/Sources/Contour/Transport/RabbitMQ/BusConfigurationEx.cs
index fcc4219..e816fb1 100644
--- a/Sources/Contour/Transport/RabbitMQ/BusConfigurationEx.cs
+++ b/Sources/Contour/Transport/RabbitMQ/BusConfigurationEx.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using Contour.Configuration;
@@ -127,5 +127,14 @@ public static IBusConfigurator UseRabbitMq(this IBusConfigurator busConfigurator
return busConfigurator;
}
+
+ public static bool RmqUseAsyncConsuming { get; private set; }
+
+ // Костыль, чтобы не тянеть в общую конфигурацию специфичную для эксперимента настройку
+ public static IBusConfiguration ConfigureRabbitMq(this IBusConfiguration busConfigurator, bool asyncConsuming)
+ {
+ RmqUseAsyncConsuming = asyncConsuming;
+ return busConfigurator;
+ }
}
}
diff --git a/Sources/Contour/Transport/RabbitMQ/Internal/Listener.cs b/Sources/Contour/Transport/RabbitMQ/Internal/Listener.cs
index 68306ff..e371967 100644
--- a/Sources/Contour/Transport/RabbitMQ/Internal/Listener.cs
+++ b/Sources/Contour/Transport/RabbitMQ/Internal/Listener.cs
@@ -1,4 +1,4 @@
-using Contour.Transport.RabbitMQ.Topology;
+using Contour.Transport.RabbitMQ.Topology;
using RabbitMQ.Client;
namespace Contour.Transport.RabbitMQ.Internal
@@ -464,7 +464,32 @@ private async Task ConsumerTaskMethod(CancellationToken token)
{
try
{
- var consumer = this.InitializeConsumer(token, out var channel);
+ Func startConsuming;
+ if (BusConfigurationEx.RmqUseAsyncConsuming)
+ {
+ var consumer = this.InitializeAsyncConsumer(token, out var channel);
+ startConsuming = () =>
+ {
+ this.StartConsumingAsync(consumer, channel, token);
+ return Task.CompletedTask;
+ };
+ }
+ else
+ {
+ var consumer = this.InitializeConsumer(token, out var channel);
+ startConsuming = async () =>
+ {
+ this.StartConsuming(consumer, channel);
+
+ this.logger.Info($"Listner {this} start consuming.");
+
+ while (!token.IsCancellationRequested)
+ {
+ var message = consumer.Dequeue();
+ await this.Deliver(this.BuildDeliveryFrom(channel, message));
+ }
+ };
+ }
var waitSecond = 0;
// если шина так и не стала готова работать, то не смысла начинать слушать сообщения, что бы потом их потерять
@@ -486,17 +511,9 @@ private async Task ConsumerTaskMethod(CancellationToken token)
}
}
- this.StartConsuming(consumer, channel);
-
- this.logger.Info($"Listner {this} start consuming.");
-
- while (!token.IsCancellationRequested)
- {
- var message = consumer.Dequeue();
- await this.Deliver(this.BuildDeliveryFrom(channel, message));
- }
+ await startConsuming();
}
- catch (OperationCanceledException)
+ catch (OperationCanceledException e) when (e.CancellationToken == token)
{
this.logger.Info("Consume operation of listener has been canceled");
}
@@ -527,8 +544,8 @@ private Expectation CreateExpectation(string correlationId, Type expectedRespons
}
return new Expectation(d => this.BuildResponse(d, expectedResponseType), timeoutTicket);
- }
-
+ }
+
private CancellableQueueingConsumer InitializeConsumer(CancellationToken token, out RabbitChannel channel)
{
// Opening a new channel may lead to a new connection creation
@@ -542,21 +559,97 @@ private CancellableQueueingConsumer InitializeConsumer(CancellationToken token,
this.ReceiverOptions.GetQoS().Value);
}
- var consumer = channel.BuildCancellableConsumer(token);
-
+ var consumer = channel.BuildCancellableConsumer(token);
+
+
+ return consumer;
+ }
+
+ private void StartConsuming(IBasicConsumer consumer, RabbitChannel channel)
+ {
+ var tag = channel.StartConsuming(
+ this.endpoint.ListeningSource,
+ this.ReceiverOptions.IsAcceptRequired(),
+ consumer);
+
+ this.logger.Trace(
+ $"A consumer tagged [{tag}] has been registered in listener of [{string.Join(",", this.AcceptedLabels)}]");
+ }
+
+
+ private AsyncEventingBasicConsumer InitializeAsyncConsumer(CancellationToken token, out RabbitChannel channel)
+ {
+ // Opening a new channel may lead to a new connection creation
+ channel = this.connection.OpenChannel(token);
+ channel.Shutdown += this.OnChannelShutdown;
+ this.channels.Add(channel);
+
+ if (this.ReceiverOptions.GetQoS().HasValue)
+ {
+ channel.SetQos(
+ this.ReceiverOptions.GetQoS().Value);
+ }
+
+ var consumer = channel.BuildConsumer();
return consumer;
}
- private void StartConsuming(IBasicConsumer consumer, RabbitChannel channel)
+ private void StartConsumingAsync(AsyncEventingBasicConsumer consumer, RabbitChannel channel, CancellationToken token)
{
- var tag = channel.StartConsuming(
+ consumer.Received += (s, e) => HandleMessage(e);
+
+ string tag = string.Empty;
+
+ async Task HandleMessage(BasicDeliverEventArgs args)
+ {
+ RabbitDelivery delivery = null;
+ try
+ {
+ delivery = this.BuildDeliveryFrom(channel, args);
+ }
+ catch (Exception e)
+ {
+ this.logger.Fatal(x => x("Delivery object has not been constructed, fetch a follow messages of the consumer for '{0}' is unpossible.", this.endpoint.ListeningSource.Address), e);
+ throw;
+ }
+
+ try
+ {
+ await this.Deliver(delivery);
+ }
+ catch (Exception e)
+ {
+ this.OnFailure(delivery, e);
+ }
+ }
+
+
+ CancellationTokenRegistration cancellationCallbackRegistration = default;
+
+ void UnsubscribeConsumer()
+ {
+ channel.StopConsuming(tag);
+ cancellationCallbackRegistration.Dispose();
+ }
+
+ cancellationCallbackRegistration = token.Register(UnsubscribeConsumer);
+
+ if (token.IsCancellationRequested)
+ {
+ UnsubscribeConsumer();
+ return;
+ }
+
+ tag = channel.StartConsuming(
this.endpoint.ListeningSource,
this.ReceiverOptions.IsAcceptRequired(),
consumer);
this.logger.Trace(
$"A consumer tagged [{tag}] has been registered in listener of [{string.Join(",", this.AcceptedLabels)}]");
+
+ this.logger.Info($"Listner {this} start consuming.");
}
private void OnChannelShutdown(IChannel channel, ShutdownEventArgs args)
diff --git a/Sources/Contour/Transport/RabbitMQ/Internal/RabbitBus.cs b/Sources/Contour/Transport/RabbitMQ/Internal/RabbitBus.cs
index 3aefdb2..b7774a2 100644
--- a/Sources/Contour/Transport/RabbitMQ/Internal/RabbitBus.cs
+++ b/Sources/Contour/Transport/RabbitMQ/Internal/RabbitBus.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
@@ -37,9 +37,10 @@ public RabbitBus(BusConfiguration configuration)
this.cancellationTokenSource = new CancellationTokenSource();
var completion = new TaskCompletionSource