0

I've done quite a bit of searching but I can't find a definitive answer to this question. I also can't find anything in the documentation that makes it absolutely clear (to me).

Is it safe to call BasicAck/BasicReject on multiple different threads, potentially at the same time?

An example:

var consumer = new EventingBasicConsumer(channel);
consumer.Received += (sender, ea) =>
{
  _ = Task.Run(async () =>
  {
    // simulate processing time
    await Task.Delay(rand.Next(2000, 10001));

    // send acknowledgement
    channel.BasicAck(ea.DeliveryTag, false);
  });
}

If the answer is no, what is the correct way to concurrently process multiple messages from the queue, and acknowledge as processing completes?

Theodor Zoulias
  • 34,835
  • 7
  • 69
  • 104
LongTom
  • 11
  • Welcome to StackOverflow. One way to do that is to dispatch messages to workers. Let's say you have 20 workers then you can use round robin to decide that which worker should process the current message. So, you 20 messages can be processed in parallel and each message is processed only by one of the workers. – Peter Csala Jul 16 '21 at 11:33
  • Thanks @PeterCsala. Undertstood, but after a worker has finished processing a message, is it safe for the worker to call channel.BasicAck, keeping in mind other workers may be making the call at the same time? – LongTom Jul 16 '21 at 12:03
  • As a side note, the `_ = Task.Run(...` creates a fire-and-forget task, whose potential failure will pass unnoticed. Making your event handler `async` (`consumer.Received += async (sender, ea) =>...`) should be more responsible in that regard. [`async void`](https://learn.microsoft.com/en-us/archive/msdn-magazine/2013/march/async-await-best-practices-in-asynchronous-programming#avoid-async-void) methods do not hide their failure under the carpet. – Theodor Zoulias Jul 16 '21 at 12:12
  • Thanks @TheodorZoulias, it's just an example to demonstrate how BasicAck might end up being called on multiple threads. – LongTom Jul 16 '21 at 12:51
  • [Based on this](https://stackoverflow.com/questions/12024241/c-sharp-rabbitmq-client-thread-safety) `channel` is not thread-safe. – Peter Csala Jul 16 '21 at 12:55
  • 1
    @PeterCsala I can find examples of people saying one way or the other, which is why I'm not sure which is true. Example here: https://stackoverflow.com/questions/40338774/concurrency-in-rabbitmq – LongTom Jul 16 '21 at 13:13
  • Based on the implementation of [BasicAck](https://github.com/rabbitmq/rabbitmq-dotnet-client/blob/main/projects/RabbitMQ.Client/client/framing/Model.cs#L240) it calls the [ModelSend](https://github.com/rabbitmq/rabbitmq-dotnet-client/blob/main/projects/RabbitMQ.Client/client/impl/ModelBase.cs#L388) which uses a `_flowControlBlock` variable. And that is a `ManualResetEventSlim`, so according to my understanding it prevents multiple `Session.Transmit`. – Peter Csala Jul 16 '21 at 13:42
  • It calls the version of ```ModelSend``` that takes a single parameter though, which omits the ```_flowControlBlock``` variable... I think. – LongTom Jul 16 '21 at 14:17

0 Answers0