Master RabbitMQ Dead Letter Queues: When and How Messages Are Redirected
This guide explains RabbitMQ dead‑letter queues, covering the conditions that turn messages into dead letters, how to configure exchanges and queues with x‑dead‑letter‑exchange, TTL, and max‑length, and provides step‑by‑step Spring Boot code examples for testing each scenario.
Environment: Spring Boot 2.3.10, RabbitMQ 3.8.12, Erlang 23.2.5
Dead Letter Queue Introduction
Messages become dead letters when any of the following occurs:
Consumer calls
basic.rejector
basic.nackwith
requeue=false.
Message TTL expires (queue created with
x-message-ttl) or the queue exceeds its length limit.
Note: Queue expiration set by
x-expiresdoes not generate dead letters.
A dead‑letter exchange is a normal exchange and can be of any type.
When creating a queue, specify
x-dead-letter-exchangeand optionally
x-dead-letter-routing-keyto redirect dead letters to the designated exchange.
Setup Environment
Create the normal business exchange and queue.
Declare a
topicexchange named
business-exchange.
Declare a
fanoutexchange named
dead-exchange(the dead‑letter exchange).
Create
business-queueand bind it to
business-exchange, setting
x-dead-letter-exchangeto the previously created dead‑letter exchange (no routing key needed because the dead‑letter exchange is
fanout).
Test
Method 1: Consumer rejects a message using
basic.rejector
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 reject scenario
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>When the message content is "1", the listener rejects it, and the message is routed to the dead‑letter queue.
Sending normal messages shows they are delivered to the original queue, while rejected messages appear in the dead‑letter queue.
Method 2: Message TTL Expiration
Recreate
business-queuewith
x-message-ttl=10000(10 seconds) and bind it to the exchange.
After 10 seconds the expired messages are automatically transferred to the dead‑letter queue.
Method 3: Queue Length Limit
Delete the existing
bussiness-queueand recreate it with
x-max-length=3. Any message beyond the third is sent to the dead‑letter queue.
Publish three messages; they stay in the queue. Publishing a fourth message causes the excess to be redirected to the dead‑letter queue.
These three methods demonstrate how RabbitMQ dead‑letter queues work and the situations that cause messages to be forwarded.
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.