How to Implement Delayed Message Delivery with RabbitMQ’s Plugin in Spring Boot

This article explains why traditional delay solutions like Redis expiration, database polling, or JVM DelayQueue are inefficient, then demonstrates step‑by‑step how to configure RabbitMQ’s delayed‑queue plugin, create exchanges, queues, and bindings in Spring Boot, and send and consume delayed messages with code examples.

IT Architects Alliance
IT Architects Alliance
IT Architects Alliance
How to Implement Delayed Message Delivery with RabbitMQ’s Plugin in Spring Boot

Background

Many applications require delayed message delivery, e.g., order‑confirmation after a fixed period or ticket‑reservation timeouts. Traditional solutions such as Redis TTL, database polling, or JVM DelayQueue cause high memory pressure, excessive I/O, or lack persistence.

RabbitMQ Delayed‑Queue Plugin

Since RabbitMQ 3.6.x an official delayed‑queue plugin is available. After placing the plugin file in the plugins directory and enabling it, a queue can hold a message for a configurable delay before routing it to consumers.

Spring Boot Configuration

Define a delayed exchange, a durable queue, and a binding in a @Configuration class. The exchange must be declared with the argument x-delayed-message=topic or by calling exchange.setDelayed(true).

import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.HashMap;
import java.util.Map;

@Configuration
public class MQConfig {
    public static final String LAZY_EXCHANGE = "Ex.LazyExchange";
    public static final String LAZY_QUEUE = "MQ.LazyQueue";
    public static final String LAZY_KEY = "lazy.#";

    @Bean
    public TopicExchange lazyExchange() {
        Map<String, Object> args = new HashMap<>();
        args.put("x-delayed-message", "topic");
        TopicExchange exchange = new TopicExchange(LAZY_EXCHANGE, true, false, args);
        exchange.setDelayed(true); // enable delayed routing
        return exchange;
    }

    @Bean
    public Queue lazyQueue() {
        return new Queue(LAZY_QUEUE, true);
    }

    @Bean
    public Binding lazyBinding() {
        return BindingBuilder.bind(lazyQueue()).to(lazyExchange()).with(LAZY_KEY);
    }
}

Sending Delayed Messages

When publishing, use a MessagePostProcessor to set the x-delay header (or call msg.getMessageProperties().setDelay(milliseconds)). The message should be marked persistent.

import com.anqi.mq.config.MQConfig;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageDeliveryMode;
import org.springframework.amqp.core.MessagePostProcessor;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.Date;

@Component
public class MQSender {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void sendLazy(Object payload) {
        rabbitTemplate.setMandatory(true);
        // confirmCallback and returnCallback can be set as needed
        CorrelationData correlationData = new CorrelationData("msg-" + new Date().getTime());
        rabbitTemplate.convertAndSend(
            MQConfig.LAZY_EXCHANGE,
            "lazy.boot",
            payload,
            new MessagePostProcessor() {
                @Override
                public Message postProcessMessage(Message msg) throws AmqpException {
                    msg.getMessageProperties().setDeliveryMode(MessageDeliveryMode.PERSISTENT);
                    // delay in milliseconds, e.g., 6000 ms (6 s)
                    msg.getMessageProperties().setDelay(6000);
                    return msg;
                }
            },
            correlationData);
    }
}

Consuming Delayed Messages

A listener annotated with @RabbitListener receives messages from the delayed queue after the configured interval. The listener should acknowledge the message.

import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;
import java.io.IOException;

@Component
public class MQReceiver {
    @RabbitListener(queues = "MQ.LazyQueue")
    @RabbitHandler
    public void onLazyMessage(Message msg, Channel channel) throws IOException {
        long deliveryTag = msg.getMessageProperties().getDeliveryTag();
        channel.basicAck(deliveryTag, false);
        System.out.println("lazy receive " + new String(msg.getBody()));
    }
}

Test Verification

A simple JUnit test sends a message with a 6‑second delay and verifies that the consumer prints the payload after the expected interval.

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

@SpringBootTest
@RunWith(SpringRunner.class)
public class MQSenderTest {
    @Autowired
    private MQSender mqSender;

    @Test
    public void sendLazy() throws Exception {
        String msg = "hello spring boot";
        mqSender.sendLazy(msg + ":");
    }
}

Running the test prints lazy receive hello spring boot: after approximately six seconds, confirming that the delayed‑queue plugin provides reliable, persistent delayed messaging without the drawbacks of Redis TTL, database polling, or in‑memory queues.

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.

BackendJavaSpring BootMessage QueueRabbitMQMessagingdelayed queue
IT Architects Alliance
Written by

IT Architects Alliance

Discussion and exchange on system, internet, large‑scale distributed, high‑availability, and high‑performance architectures, as well as big data, machine learning, AI, and architecture adjustments with internet technologies. Includes real‑world large‑scale architecture case studies. Open to architects who have ideas and enjoy sharing.

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.