9

I have been playing around with RabbitMq.net and the message acknowledgements. If the consumer is able to process the message you can send back an ack in the form of

channel.BasicAck(ea.DeliveryTag, false);

which will take it off the queue.

But what about if the message was unable to be processed ? maybe a temporary outage and you don't want the message taken off the queue just put to the back and carry on with the next message?

I have tried using

channel.BasicNack(ea.DeliveryTag, false, true);

but the next time round its still getting the same message and not moving to the next message in the queue

my complete code is

class Program
{
    private static IModel channel;
    private static QueueingBasicConsumer consumer;
    private static IConnection Connection;

    static void Main(string[] args)
    {
        Connection = GetRabbitMqConnection();
        channel = Connection.CreateModel();
        channel.BasicQos(0, 1, false);
        consumer = new QueueingBasicConsumer(channel);
        channel.BasicConsume("SMSQueue", false, consumer);
        while (true)
        {
            if (!channel.IsOpen)
            {
                throw new Exception("Channel is closed");
            }
            var ea = consumer.Queue.Dequeue();
            string jsonified = Encoding.UTF8.GetString(ea.Body);
            var message = JsonConvert.DeserializeObject<SmsRecords>(jsonified);
            if (ProcessMessage())
                channel.BasicAck(ea.DeliveryTag, false);
            else
                channel.BasicNack(ea.DeliveryTag, false, true);
        }
    }

    private static bool ProcessMessage()
    {
        return false;
    }

    public static IConnection GetRabbitMqConnection()
    {
        try
        {
            var connectionFactory = new ConnectionFactory
            {
                UserName = "guest",
                Password = "guest",
                HostName = "localhost"
            };
            return connectionFactory.CreateConnection();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            return null;
        }
    }
}
level_zebra
  • 1,503
  • 6
  • 25
  • 44
  • I resolved this by using a subscription and then calling BasicDeliverEventArgs basicDeliveryEventArgs = subscription.Next(); – level_zebra Feb 19 '15 at 12:51
  • 1
    How did using Subscription 'fix' the issue of keeping on running into the same messages? Either NoAck mode is on (and the server auto-acks) or Ack was sent to acknowledge processing of the message - both are wrong if the message couldn't be processed in some valid fashion but "shouldn't be lost". If Acks aren't sent then the messages will 'reappear' once the channel is closed. I suspect that the code with the Subscription simply used a larger Prefetch or something else.. (with RabbitMQ > 2.7 you can Nack-requeue to effectively put messages "to the back" of the prefetch buffer). – user2864740 Jan 24 '16 at 13:41

1 Answers1

18

This is how my company does it: If a message fails (for any reason) we nack the message into a holding queue where it sits for 10 seconds, it then gets put back into the queue to be retried. We do this loop up to 10 times, if the message is nacked 10 times then we assume it is a failure we can't recover from and we put it into a permanent dead-letter queue for investigation.

Here is the diagram: enter image description here

jhilden
  • 12,207
  • 5
  • 53
  • 76