Exploring Manual and Automatic Acknowledgment in RabbitMQ with .NET

Delivery processing acknowledgements from consumers are referred to as acknowledgements in messaging protocols. Let's learn automatic and manual ack modes in RabbitMQ.

Rahul Pulikkot Nath
Rahul Pulikkot Nath

Table of Contents

Messages picked up for processing by the consumers are not guaranteed to be successfully processed.

Hence, consumers need a mechanism for processing confirmation.

Delivery processing acknowledgements from consumers are referred to as acknowledgements in messaging protocols.

In this post, let’s learn about different acknowledgement modes and how to use them when working with RabbitMQ from a .NET application.

The concept still applies to other programming languages.

There are two acknowledgement modes supported in RabbitMQ

  • Automatic ACK
  • Manual ACK

This article is sponsored by AWS and is part of my RabbitMQ Series.

Automatic Acknowledgement From .NET Application

The message is considered to be successfully delivered immediately after it's sent.

With Automatic ACK mode, there is a higher throughput of messages getting processed at the risk of losing some messages.

It can also cause the consumer to overload if many messages are in the queue.

channel.BasicConsume("hello", autoAck: true, consumer);

When registering the consumer with the RabbitMQ channel, you can specify autoAck property true to enable automatic acknowledgement, as shown above.

However, when using Automatic acknowledgement, when there are exceptions in message consumers these messages are completely lost from the Queue.

The code below throws an exception if the message received contains the word 'exception.' This message is processed and removed from the queue, even though the consumer threw an exception while processing.

consumer.Received += (model, ea) =>
{
    var body = ea.Body.ToArray();
    var message = Encoding.UTF8.GetString(body);
    Console.WriteLine($"[x] Received message {message}");
    
    if (message.Contains("exception"))
    {
        Console.WriteLine("Error in processing");
        throw new Exception("Error in processing");
    }
    
    // Additional processing for this message
    Console.WriteLine($"Processed message {message}");
};

Manual Acknowledgement From .NET Application

With Manual Acknowledgement, the consumer explicitly marks a message as processed successfully or failed.

RabbitMQ provides different protocol methods to acknowledge the messages:
- basic.ack → positive acknowledgements
- basic.nack → negative acknowledgement (also supports multiple messages)
- basic.reject → negative acknowledgement (single message only)

To use manual acknowledgement, specify autoAck as false when registering a consumer to RabbitMQ using the channel.

channel.BasicConsume("hello", autoAck: false, consumer);

Delivery Tags

Delivery Tags are used to acknowledge deliveries. Every message delivered on a channel has an associated delivery tag.

Delivery tags are scoped to a channel, so the same channel must acknowledge a message using the received tag. Acknowledging messages with a delivery tag from a different channel will cause an exception and close that channel.

Below is the sample code in the RabbitMQ consumer to acknowledge (BasicAck) and reject (BasicReject) a message based on the consumer logic.

consumer.Received += (model, ea) =>
{
    var body = ea.Body.ToArray();
    var message = Encoding.UTF8.GetString(body);
    Console.WriteLine($"[x] Received message {message}");
    
    if (message.Contains("exception"))
    {
        Console.WriteLine("Error in processing");
        channel.BasicReject(ea.DeliveryTag, false);
        throw new Exception("Error in processing");
    }
    
    // Additional processing for this message
    Console.WriteLine($"Processed message {message}");
    channel.BasicAck(deliveryTag: ea.DeliveryTag, false);
};

Delivery Acknowledgement Timeout

If the consumer does not reply with a message within the Delivery Acknowledgement Timeout period, the channel will be closed with an PRECONDITION_FAILED exception. All outstanding deliveries on that channel will be re-queued.

You can configure the consumer_timeout value for your RabbitMQ instance.

In RabbitMQ hosted on Amazon MQ, you can do that under Amazon MQ → Configurations as shown below and assign that configuration to your RabbitMQ instance.

RabbitMQ configuration in Amazon MQ to override the consumer_timeout value to be 30 seconds instead of the default 30 minutes.
RabbitMQ configuration in Amazon MQ to override the consumer_timeout value to be 30 seconds instead of the default 30 minutes.

How you configure it will differ based on how you host your RabbitMQ instance.

Rabbit NACK vs Reject

The only difference between nack and reject is that, nack supports rejecting multiple deliveries with a single call. It was for this reason nack was introduced as a protocol extension.

Automatic acknowledgment is generally considered unsafe and unsuitable for all workloads. Choose only for scenarios where you don't need a guarantee on the message being processed.

For all other scenarios, manually acknowledge your messages!

RabbitMQAWS