Rabbitmq Ack or Nack, leaving messages on the queue

13,445

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

Share:
13,445

Related videos on Youtube

level_zebra
Author by

level_zebra

Updated on June 04, 2022

Comments

  • level_zebra
    level_zebra almost 2 years

    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
      level_zebra about 9 years
      I resolved this by using a subscription and then calling BasicDeliverEventArgs basicDeliveryEventArgs = subscription.Next();
    • user2864740
      user2864740 over 8 years
      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).
  • Jerald Baker
    Jerald Baker about 4 years
    How do you nack message "into a holding queue"? doesn't it automatically get re-queued in the original queue?