Dead Letter Queue
Handle failed KubeMQ queue messages with dead-letter routing in Node.js, diverting poison messages after retries are exhausted.
Which to use
This page is the task-oriented walkthrough: send a message with DLQ routing configured, let it exhaust retries, and consume the diverted message. For the policy field reference — maxReceiveCount/maxReceiveQueue defaults and edge cases — see Dead Letter Policy.
Overview
A dead-letter queue (DLQ) gives a poison message somewhere to go instead of looping through consumers forever. When a message keeps failing — a malformed payload, a downstream outage, a handler bug — retrying it forever wastes consumer cycles and blocks everything behind it. A DLQ takes that decision out of your hands: past a set number of failed attempts, the broker diverts the message to a separate channel instead of retrying it again.
Routing runs on two policy fields passed to createQueueMessage(): maxReceiveCount and maxReceiveQueue. Every failed delivery — a missing ack(), a reject, or an expired visibility window — increments receiveCount; past the threshold, the broker reroutes the message to the DLQ instead of redelivering it. The DLQ itself is an ordinary queue, consumed like any other channel.
Gotchas: the DLQ doesn't drain itself — a dedicated consumer must watch it. The count increments on any failed delivery, not just deliberate rejections — a slow consumer that lets the visibility window lapse counts the same as an explicit nack. A typo in the DLQ channel name quietly creates an unrelated channel instead of failing loudly.
Prerequisites
- KubeMQ server running on
localhost:50000 - Node.js SDK installed (
npm install kubemq-js)
Code
/**
* Example: Dead-Letter Queue with maxReceiveCount
*
* Demonstrates configuring messages to automatically move to a dead-letter
* queue after a specified number of delivery attempts. This prevents poison
* messages from blocking the queue.
*
* Prerequisites:
* - KubeMQ server running on localhost:50000
*
* Run: npx tsx examples/queues/dead-letter-queue.ts
*/
import { KubeMQClient, createQueueMessage } from 'kubemq-js';
async function main(): Promise<void> {
const client = await KubeMQClient.create({
address: 'localhost:50000',
clientId: 'js-queues-dead-letter-queue-client',
});
try {
// Send a message with a dead-letter policy: after 3 failed deliveries,
// automatically move to the dead-letter queue.
await client.sendQueueMessage(
createQueueMessage({
channel: 'js-queues.dead-letter-queue',
body: 'Order #5001: ship to warehouse B',
policy: {
maxReceiveCount: 3,
maxReceiveQueue: 'js-queues.dead-letter-queue-dlq',
},
}),
);
console.log('Sent message with DLQ policy (max 3 attempts)');
// Simulate processing failure — receive but don't ack.
// After visibility timeout, the message becomes available again.
// After 3 total receives, it moves to 'js-queues.dead-letter-queue-dlq'.
const messages = await client.receiveQueueMessages({
channel: 'js-queues.dead-letter-queue',
waitTimeoutSeconds: 5,
});
for (const msg of messages) {
console.log('Received (attempt #%d):', msg.receiveCount, new TextDecoder().decode(msg.body));
// Intentionally not acking — simulating a processing failure.
}
} finally {
await client.close();
}
}
main().catch(console.error);
How It Works
- The
policyfield increateQueueMessage()attaches a delivery policy:maxReceiveCount: 3caps attempts andmaxReceiveQueuenames the dead-letter channel. - Intentionally not calling
msg.ack()simulates a processing failure; after the visibility timeout the server makes the message available for re-delivery. - After the third failed attempt, the server automatically moves the message to
js-queues.dead-letter-queue-dlq— the consumer never has to implement the DLQ routing logic. msg.receiveCountincrements on each delivery attempt; inspect it to determine how many times a message has been retried before deciding whether to process or reject it.
Related
- Dead Letter Policy — field-level reference for
maxReceiveCountandmaxReceiveQueue - Pattern overview
- Node.js SDK Reference
- Send & Receive
- Ack All
Was this page helpful?