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.

Programmer DD
Programmer DD
Programmer DD
How to Implement RabbitMQ Requeue with Spring Cloud Stream for Reliable Message Retry

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-topic

Run 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=true

Updated 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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

DLQrequeuemessage-retryspring-cloud-stream
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.