How to Implement RabbitMQ Requeue with Spring Cloud Stream for Reliable Message Retry
This tutorial shows how to configure Spring Cloud Stream's RabbitMQ binder to requeue failed messages, provides a complete Java example with producer and consumer code, explains the difference from default retry, and demonstrates using a dead‑letter queue to prevent message buildup.
Application Scenario
Previously we introduced Spring Cloud Stream's default retry mechanism. This article demonstrates the alternative retry provided by the RabbitMQ binder: requeue.
Hands‑on Example
Set up a project that produces and consumes messages. The following Java code defines the Spring Boot application, a REST controller for sending messages, and a listener that deliberately throws an exception to simulate consumption failure.
@EnableBinding(TestApplication.TestTopic.class)
@SpringBootApplication
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
}
@RestController
static class TestController {
@Autowired
private TestTopic testTopic;
@GetMapping("/sendMessage")
public String messageWithMQ(@RequestParam String message) {
testTopic.output().send(MessageBuilder.withPayload(message).build());
return "ok";
}
}
@Component
static class TestListener {
private int count = 1;
@StreamListener(TestTopic.INPUT)
public void receive(String payload) {
log.info("Received payload : " + payload + ", " + count);
throw new RuntimeException("Message consumer failed!");
}
}
interface TestTopic {
String OUTPUT = "example-topic-output";
String INPUT = "example-topic-input";
@Output(OUTPUT)
MessageChannel output();
@Input(INPUT)
SubscribableChannel input();
}
}The example includes both message production and consumption, with the consumer intentionally throwing an exception.
Configuration
Before starting the application, configure the physical destinations and group:
spring.cloud.stream.bindings.example-topic-input.destination=test-topic
spring.cloud.stream.bindings.example-topic-input.group=stream-exception-handler
spring.cloud.stream.bindings.example-topic-input.consumer.max-attempts=1
spring.cloud.stream.rabbit.bindings.example-topic-input.consumer.requeue-rejected=true
spring.cloud.stream.bindings.example-topic-output.destination=test-topicRun the application and call http://localhost:8080/sendMessage?message=hello. The consumer will repeatedly fail, and because requeue-rejected=true, the failed message is placed back onto the queue for another retry.
Deep Thinking
Question 1: How does the requeue‑based retry differ from the default max-attempts retry?
Default retry reprocesses the same message within the same delivery, while requeue creates a new delivery by putting the message back onto the queue, resulting in multiple distinct messages.
Question 2: What if a message keeps failing and accumulates?
Combine the requeue approach with a dead‑letter queue (DLQ). Enable DLQ binding and modify the listener to throw AmqpRejectAndDontRequeueException after a certain number of attempts, sending the message to the DLQ instead of endless requeue.
DLQ Configuration
spring.cloud.stream.rabbit.bindings.example-topic-input.consumer.auto-bind-dlq=trueUpdated listener example:
@StreamListener(TestTopic.INPUT)
public void receive(String payload) {
log.info("Received payload : " + payload + ", " + count);
if (count == 3) {
count = 1;
throw new AmqpRejectAndDontRequeueException("tried 3 times failed, send to dlq!");
} else {
count++;
throw new RuntimeException("Message consumer failed!");
}
}When the specific exception is thrown, the message is routed to the DLQ, preventing endless accumulation.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
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.
