AMQP and RabbitMQ basic.ack, basic.reject and requeue

Exposing basic.ack and basic.reject behavior in an AMQP-based messaging abstraction can be critical.

Some misunderstandings about ack/reject: first, on the issue of either being an ‘extra’ operation – An AMQP ack, reject, or Rabbit nack to an AMQP broker is not equal to publishing a message to a broker. On the issue of this being an extraneous operation, when a consumer receives a message (removing it from a queue), the Rabbit server is aware of that and an acknowledge is needed to confirm this. Automatically ack-ing all received messages is not a case I agree with, no matter what abstraction you provide, nor is it good practice. It should to be configurable and provide the ability to do error handling in unsuccessful application scenarios.

basic.ack
Using the rabbit java client: where false is for multiple acks

channel.basicAck(delivery.getEnvelope().getDeliveryTag(), false);

basic.reject

channel.basicReject(delivery.getEnvelope().getDeliveryTag(), requeue);

Maybe an application is in a post-stop/pre-destroy phase. Or perhaps the message content was inappropriate (an error in the sender that composed the message) – nothing whatsoever to do with routing, AMQP, Rabbit but a user/programmer error, a lifecycle issue, and so forth.

basic.reject and requeue
basic.reject could either redeliver the message or dead-letter it

a) If you supply requeue=false the broker will discard the message – This is useful from a error handling point of view; if your application cannot process a particular message, you can get rid of it.

b) if you supply requeue=true, it will release it back on to the queue, to be delivered again – This  is useful for a consumer to decide not to deal with a delivered message, and place it back on the queue.

Rabbit re-enqueues the message and treats it as though it were completely new. This means a consumer can receive it again when message it has rejected. This could be a consumer for a ‘vcaf instance queue’ where for some reason, maybe it is dealing with a fatal error and going to be restarted, should send a basic.reject and requeue=true so that when it is restarted and initialized, it can successfully re-receive the message and process it.

AsyncConsumer consumer = new  AbstractQueueingConsumer(connectionFactory, queue, autoAck) {
     @Override public void handle(Channel channel,  QueueingConsumer.Delivery delivery) {
             ...application logic...
             if (some application case...) reject(channel,  delivery, true); //boolean requeue
             else acknowledge(channel, delivery);
        }
};

Share/Save

Leave a Reply