Master RabbitMQ Dead-Letter Queues: When and How Messages Get Redirected
This guide explains RabbitMQ dead-letter queues, detailing the conditions that cause messages to become dead letters, how to configure exchanges and queues with x-dead-letter parameters, and demonstrates three testing methods—reject/nack, TTL expiration, and max-length overflow—using Spring Boot code examples.
Environment
Spring Boot 2.3.10 + RabbitMQ 3.8.12 + Erlang 23.2.5
Dead Letter Queue Introduction
Messages in a queue can become "dead letters" and be republished to an exchange when any of the following events occur:
The consumer calls basic.reject or basic.nack with the requeue parameter set to false .
The message has a TTL (set via x-message-ttl on the queue) and expires, or the queue exceeds its length limit and discards messages.
Note: Queue expiration (set via
x-expires) does not cause its messages to become dead letters.
A dead‑letter exchange is a normal exchange and can be of any type.
When creating a queue, you can specify
x-dead-letter-exchangeand optionally
x-dead-letter-routing-keyto redirect messages that meet the above conditions.
Prepare Environment
Create the normal business exchange and queue needed for the workflow.
Create a
business-exchangeof type
topic:
Create a dead‑letter exchange named
dead-exchangeof type
fanout:
Create the business queue
business-queueand bind it to the exchange, setting
x-dead-letter-exchangeto the dead‑letter exchange (no routing key needed because the dead‑letter exchange is
fanout).
Test
Method 1: Consumer rejects with basic.reject or basic.nack
Send message endpoint:
<code>@GetMapping("/sendDeadLetter")
public Object sendDeadLetter(String msg) {
ms.sendDeadLetter(msg);
return "success";
}
public void sendDeadLetter(String msg) {
logger.info("准备发送消息:{}", msg);
rabbitTemplate.convertAndSend("business-exchange", "be.1", msg);
}
</code>Message listener:
<code>@Component
public class MessageListener {
@RabbitListener(queues = { "bussiness-queue" })
@RabbitHandler
public void listener1(Message message, Channel channel) {
System.out.println("接受到消息.....income");
byte[] body = message.getBody();
MessageProperties mps = message.getMessageProperties();
String content = new String(body, Charset.forName("UTF-8"));
try {
// Simulate rejection
if ("1".equals(content)) {
System.out.println("拒绝消息:1");
channel.basicReject(mps.getDeliveryTag(), false);
return;
}
System.out.println("接受到消息来自交换机: 【" + mps.getReceivedExchange() + "】, 队列:【" + mps.getConsumerQueue() + "】:\n\t\t内容: " + content);
channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
} catch (Exception e) {
e.printStackTrace();
try {
channel.basicReject(mps.getDeliveryTag(), false);
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
</code>The listener rejects the message when the payload is "1".
Send a normal message:
Send a rejected message (payload "1"):
View the queues – the rejected message appears in the dead‑letter queue.
Method 2: Set message TTL (expiration)
Recreate
business-queuewith
x-message-ttlset to 10000 ms (10 seconds).
Bind the queue to the exchange.
Send a message and wait 10 seconds; the expired message is automatically routed to the dead‑letter queue.
Method 3: Set maximum queue length
Delete the existing
bussiness-queueand recreate it with
x-max-length=3. Any message beyond the third is sent to the dead‑letter queue.
Send three messages – they stay in the queue. Sending a fourth message causes the oldest message to be moved to the dead‑letter queue.
The overflow message appears in the dead‑letter queue.
These examples demonstrate the situations in which RabbitMQ redirects messages to a dead‑letter queue.
End of tutorial.
Spring Full-Stack Practical Cases
Full-stack Java development with Vue 2/3 front-end suite; hands-on examples and source code analysis for Spring, Spring Boot 2/3, and Spring Cloud.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.