Acknowledgements, Dead-Letter Queues, and Retries
Guarantee delivery with manual acks, handle poison messages, and implement retry and dead-letter flows.
Why Acknowledgements Matter
By default, when a consumer receives a message from RabbitMQ it must tell the broker whether the message was processed successfully. This signal is called an acknowledgement (ack).
If you enable auto-ack, RabbitMQ deletes a message the instant it is delivered. If your worker then crashes mid-processing, the message is gone forever. With manual acks, the broker keeps the message until you confirm it, and re-delivers it if the consumer dies.
- auto-ack: fast, but at-most-once delivery (can lose messages)
- manual ack: safe, gives you at-least-once delivery
For any job that does real work (charging a card, sending email, writing to a DB), you almost always want manual acks.
Consuming With Manual Acks
Using the amqplib library, you pass { noAck: false } to channel.consume to enable manual acknowledgement. After your handler finishes successfully, you call channel.ack(msg).
Until you ack, RabbitMQ considers the message unacked and will redeliver it if the channel or connection closes.
const amqp = require('amqplib');
async function start() {
const conn = await amqp.connect('amqp://localhost');
const channel = await conn.createChannel();
const queue = 'orders';
await channel.assertQueue(queue, { durable: true });
channel.consume(queue, async (msg) => {
if (msg === null) return;
const order = JSON.parse(msg.content.toString());
console.log('Processing order', order.id);
// ... do real work here ...
channel.ack(msg); // confirm success
}, { noAck: false });
}
start();All lessons in this course
- Producers, Consumers, and the AMQP Model
- Exchange Types: Direct, Topic, Fanout, and Headers
- Acknowledgements, Dead-Letter Queues, and Retries
- Work Queues, Prefetch, and Competing Consumers