Does the RabbitMQ .NET client have any sort of asynchronous support? I\'d like to be able to connect and consume messages asynchronously, but haven\'t found a way to do eith
Rabbit supports dispatching to asynchronous message handlers using the AsyncEventingBasicConsumer
class. It works similarly to the EventingBasicConsumer
, but allows you to register an callback which returns a Task
. The callback is dispatched to and the returned Task
is awaited by the RabbitMQ client.
var factory = new ConnectionFactory
{
HostName = "localhost",
DispatchConsumersAsync = true
};
using(var connection = cf.CreateConnection())
{
using(var channel = conn.CreateModel())
{
channel.QueueDeclare("testqueue", true, false, false, null);
var consumer = new AsyncEventingBasicConsumer(model);
consumer.Received += async (o, a) =>
{
Console.WriteLine("Message Get" + a.DeliveryTag);
await Task.Yield();
};
}
Console.ReadLine();
}
there is no async/await support built in to the RabbitMQ .NET client at this point. There is an open ticket for this on the RabbitMQ .NET Client repository
To summarize current async
/TPL
support:
AsyncEventingBasicConsumer
which you can register events for and return a Task
.HandleBasicDeliver
and return a Task
. Original PR here (looks like it was also introduced in 5.0?)async
operations, but I don't see any specific links to that effort.There is AsyncEventingBasicConsumer
and all that it does, is await
ing your async "event handlers" when message is received. That's the only thing that is made asynchronous here. Typically you don't get any profits from this, because you have only one "handler". Messages are still processed one-by-one. They are processed synchronously! Also you lose control of exception handling because awaiting is done inside Consumer.
Let me guess that by asynchronous message processing you mean some degree of parallelism.
What i ended up using is ActionBlock
from TPL Dataflow. ActionBlock
runs as much tasks as you configured it to, managing awaits and parellelism. Since it operates on Tasks, not Threads, it can manage with less resources, as long as they are truly asynchronous.
EventingBasicConsumer
calls actionBlock.Post(something)
.ack
them: model.BasicQos(0, N, true);
MaxDegreeOfParallelism
property which also needs to be set to N.async Task
s which receive data posted earlier by Consumer. Tasks should not throw because ActionBlock stops all processing on exceptions.CancellationToken
around and correctly wait for ActionBlock to finish all running Tasks: actionBlock.Complete(); await actionBlock.Completion;