Over a million developers have joined DZone.

RabbitMQ Retries Using Spring Integration

DZone's Guide to

RabbitMQ Retries Using Spring Integration

Sometimes performing basic tasks can be made harder through abstraction frameworks such as Spring Integration. If you want to do retries in RabbitMQ then find out how here!

· Java Zone
Free Resource

Learn how to troubleshoot and diagnose some of the most common performance issues in Java today. Brought to you in partnership with AppDynamics.

TL;DR the flow looks a little convoluted and is shown in this diagram:

The gist of the flow is :

1. A Work dispatcher creates "Work Unit"(s) and sends it to a RabbitMQ queue via an exchange.

2. The Work queue is set with a Dead Letter exchange. If the message processing fails for any reason the "Work Unit" ends up with the Work Unit Dead Letter Queue.

3. Work Unit Dead Letter queue is in-turn set with the Work Unit exchange as the Dead Letter Exchange, this way creating a cycle. Further, the expiration of messages in the dead letter queue is set to say 10 mins, this way once the message expires it will be back again in the Work unit queue.

4. To break the cycle the processing code has to stop processing once a certain count threshold is exceeded.

Implementation Using Spring Integration

I have covered a straight happy path flow using Spring Integration and RabbitMQ before, here I will mostly be building on top of this code.

A good part of the set-up is the configuration of the appropriate dead letter exchanges/queues, and looks like this when expressed using Spring's Java Configuration:

public class RabbitConfig {

    private ConnectionFactory rabbitConnectionFactory;

    Exchange worksExchange() {
        return ExchangeBuilder.topicExchange("work.exchange")

    public Queue worksQueue() {
        return QueueBuilder.durable("work.queue")
                .withArgument("x-dead-letter-exchange", worksDlExchange().getName())

    Binding worksBinding() {
        return BindingBuilder

    // Dead letter exchange for holding rejected work units..
    Exchange worksDlExchange() {
        return ExchangeBuilder

    //Queue to hold Deadletter messages from worksQueue
    public Queue worksDLQueue() {
        return QueueBuilder
                .withArgument("x-message-ttl", 20000)
                .withArgument("x-dead-letter-exchange", worksExchange().getName())

    Binding worksDlBinding() {
        return BindingBuilder

Note that here I have set the TTL of the Dead Letter queue to 20 seconds, this means that after 20 seconds, a failed message will be back in the processing queue. Once this set-up is in place and the appropriate structures are created in RabbitMQ, the consuming part of the code looks like this, expressed using Spring Integration Java DSL:

public class WorkInbound {

    private RabbitConfig rabbitConfig;

    public IntegrationFlow inboundFlow() {
        return IntegrationFlows.from(
                .filter("(headers['x-death'] != null) ? headers['x-death'][0].count <= 3: true", f -> f.discardChannel("nullChannel"))
                .handle("workHandler", "process")


Most of the retry logic here is handled by the RabbitMQ infrastructure, the only change here is to break the cycle by explicitly discarding the message after a certain 2 retries. This break is expressed as a filter above, looking at the header called "x-death" that RabbitMQ adds to the message once it is sent to Dead Letter exchange. The filter is admittedly a little ugly — it can likely be expressed a little better in Java code.

One more thing to note is that the retry logic could have been expressed in process using Spring Integration, however I wanted to investigate a flow where the retry times can be high (say 15 to 20 mins) which will not work well in process and is also not cluster safe as I want any instances of an application to potentially handle the retry of a message.

If you want to explore further, do try the sample at my GitHub repo.


Understand the needs and benefits around implementing the right monitoring solution for a growing containerized market. Brought to you in partnership with AppDynamics.

spring ,rabbitmq ,exchange ,spring integration ,queue ,retry

Published at DZone with permission of Biju Kunjummen, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.


Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.


{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}