What are common RabbitMQ best practices and anti-patterns?
Master RabbitMQ best practices: durable queues, publisher confirms, prefetch, manual acks and dead-letter queues, plus anti-patterns that lose messages.
Expected Interview Answer
Best practices center on durable queues with publisher confirms, bounded prefetch, acknowledgements, and dead-letter queues, while the main anti-patterns are unbounded queues, auto-ack, giant messages, and treating RabbitMQ like a database.
Design for reliability: declare durable queues and persistent messages where loss is unacceptable, enable publisher confirms, and use manual consumer acks so a crash triggers redelivery. Set a sensible prefetch (QoS) so a single consumer does not hoard thousands of unacked messages, cap queue length or use lazy queues to protect memory, and route failures to dead-letter queues for inspection. Avoid anti-patterns like publishing without confirms, using auto-ack that silently drops messages on failure, storing huge payloads (pass a reference instead), creating unbounded queues that exhaust RAM, and polling or hoarding messages as if the broker were a long-term store.
- Prevents message loss with confirms and manual acks
- Protects broker memory via prefetch limits and queue caps
- Enables graceful failure handling through dead-letter queues
- Keeps consumers balanced and responsive
- Improves observability and recovery
AI Mentor Explanation
Good RabbitMQ practice is like a captain who rotates the bowling load evenly rather than exhausting one bowler, keeps a twelfth man ready for injuries, and reviews every dropped catch. The anti-pattern is dumping the whole over on one tired bowler and never checking who let the ball slip through.
Step-by-Step Explanation
Step 1
Make critical paths durable
Declare durable queues and mark messages persistent where loss is unacceptable, and enable publisher confirms.
Step 2
Acknowledge manually
Use manual consumer acks so an unhandled crash requeues the message instead of silently losing it under auto-ack.
Step 3
Tune prefetch
Set a bounded basicQos prefetch so consumers take a fair share and the broker stays responsive under load.
Step 4
Bound and dead-letter queues
Cap queue length or use lazy queues, and route rejected or expired messages to a dead-letter exchange for inspection.
Step 5
Keep messages small
Store large payloads elsewhere and pass a reference; never treat the broker as a database or blob store.
What Interviewer Expects
- Knowing durability requires both durable queues and persistent messages
- Understanding publisher confirms and manual acknowledgements
- Explaining prefetch/QoS and why it matters
- Using dead-letter queues for failure handling
- Recognizing anti-patterns like auto-ack and unbounded queues
Common Mistakes
- Using auto-ack and silently losing messages on consumer failure
- Leaving prefetch unbounded so one consumer hoards messages
- Assuming a durable queue alone persists non-persistent messages
- Publishing without confirms and assuming delivery
- Storing large blobs in messages instead of passing references
Best Answer (HR Friendly)
“The best practices are making important messages durable, confirming they were sent and received, and limiting how many each worker takes so nobody gets overloaded. The main mistakes are assuming messages arrived without checking, letting queues grow without limit, and stuffing huge files into messages.”
Code Example
const amqp = require('amqplib')
async function consume() {
const conn = await amqp.connect('amqp://localhost')
const ch = await conn.createChannel()
// Bound prefetch so one consumer does not hoard messages
await ch.prefetch(10)
// Durable queue with a dead-letter exchange for failures
await ch.assertQueue('tasks', {
durable: true,
arguments: { 'x-dead-letter-exchange': 'tasks.dlx' }
})
ch.consume('tasks', async (msg) => {
try {
await handle(msg)
ch.ack(msg) // manual ack only after success
} catch (err) {
ch.nack(msg, false, false) // reject -> routed to DLX
}
}, { noAck: false })
}
consume()Follow-up Questions
- What is the difference between a durable queue and a persistent message?
- How does prefetch affect throughput and fairness?
- How do dead-letter queues help with poison messages?
- When would you use lazy queues?
- Why are publisher confirms preferable to transactions?
MCQ Practice
1. What does setting a prefetch (basicQos) value do?
Prefetch caps how many unacknowledged messages a consumer holds, keeping load balanced and the broker responsive.
2. Why avoid auto-ack for important work?
Auto-ack acknowledges on delivery, so a crash before processing loses the message with no redelivery.
3. Where do rejected or expired messages go when configured?
A dead-letter exchange captures rejected, expired, or overflow messages for inspection and reprocessing.
Flash Cards
Durable vs persistent? — A durable queue survives restart; the message must also be marked persistent to survive.
What is prefetch? — A QoS limit on unacknowledged messages per consumer to balance load.
Why manual ack? — So a crashed or failed consumer requeues the message instead of silently dropping it.
What is a dead-letter queue? — A queue that captures rejected, expired, or overflowed messages for inspection.
Continue Learning
Related Interview Questions
What is message acknowledgement (ack/nack) in RabbitMQ and why does it matter?
medium
How do you handle message retries and back-off in RabbitMQ?
medium
What is the difference between at-most-once, at-least-once, and exactly-once delivery?
medium
How does RabbitMQ handle flow control and back pressure?
hard