patterntypescriptMajor
Dead letter queues: capture and inspect unprocessable messages without data loss
Viewed 0 times
dead letter queuedlqpoison pillretryrabbitmq dlxkafka dlqerror handlingmessage reprocessing
Problem
A consumer receives a malformed message and throws an error. The message is either discarded (data loss) or retried indefinitely (infinite loop blocking the queue).
Solution
Configure a Dead Letter Queue (DLQ). After N failed attempts the broker routes the message to a dedicated DLQ topic/exchange for later inspection and manual reprocessing.
// RabbitMQ: configure DLX at queue creation
await channel.assertQueue('orders', {
durable: true,
arguments: {
'x-dead-letter-exchange': 'orders.dlx',
'x-max-retries': 3,
},
});
// Kafka: manually publish to DLQ on max retries
async function eachMessage({ message }: EachMessagePayload) {
const retries = parseInt(message.headers?.['x-retry-count']?.toString() ?? '0');
try {
await processMessage(message);
} catch (err) {
if (retries >= 3) await publishToDLQ(message);
else await retryWithBackoff(message, retries + 1);
}
}Why
DLQs prevent poison pills from blocking the main queue indefinitely while preserving the message for human inspection and replay after the root cause is fixed.
Gotchas
- Monitor DLQ depth — a growing DLQ is a silent alert that something is broken in your consumer logic
- Messages in the DLQ retain their original headers — use them to reconstruct the failure context
- Build a DLQ replay tool early — manually reprocessing dozens of JSON files by hand is painful
- DLQ messages should be replayed against a fixed consumer, not the broken one — validate the fix first
Context
Any message-driven system where consumer failures must not cause data loss or infinite retry loops
Revisions (0)
No revisions yet.