In many situations, we all have a need to delay queue, however, by default the RabbitMQ did not provide the queue delay related functions, however, in the previous article, scene and share the dead-letter queue of the RabbitMQ, combination of dead-letter queue and a message expiration time set, we can also realize the function of the queue delay, Let’s take a look today.

RabbitMQ has a dedicated delay queue plugin, but we’ll talk about that later.

If you haven’t read the previous article, take a look to help you understand it:

  • Do messages in RabbitMQ expire?

1. When is a delay queue needed?

Let’s talk about when we need delay queues.

Just a few simple examples.

  • In the e-commerce project, when we place an order, we generally need to pay within 20 minutes or 30 minutes. Otherwise, the order will enter the exception processing logic and be cancelled. Then entering the exception processing logic can be regarded as a delay queue.
  • I bought a smart casserole, can be used to cook porridge, before going to work to put the material into the pot, and then set a few minutes to start cooking porridge, so after work you can drink delicious porridge, then the porridge instruction can also be regarded as a delay task, in a delay queue, time to execute again.
  • The company’s conference reservation system will notify all users who have scheduled a meeting half an hour before the meeting starts.
  • If the safety work order is not processed within 24 hours, it will automatically pull up the wechat group of the enterprise to remind the relevant responsible person.
  • After placing an order for takeout, the user will remind the delivery boy that the time limit is about to expire 10 minutes later.
  • .

There are many scenarios where we need delay queues.

Some friends may say that it is more convenient to have a regular task directly. If the project has only one such delay queue scenario, then a scheduled task may seem ok, but if the project has many such scenarios, then a scheduled task is obviously not the best solution, and we can implement a general solution with delay queues.

2. Implementation idea of delay queue

The idea of delay queue implementation is also very simple, that is, the last article we said DLX (dead-letter switch) +TTL (message timeout time).

We can think of a dead letter queue as a delay queue.

To be specific:

If a message needs to be executed 30 minutes later, we set the message to be valid for 30 minutes and configure a dead-letter switch and dead-letter for the messagerouting_key, and do not set up consumers for the message queue, then 30 minutes later, the message is not consumed by consumers and entered the dead letter queue, at this time we have a consumer “squatting” in the dead letter queue, the message entered the dead letter queue, immediately consumed.

This is the idea of implementing delay queue, isn’t it very simple?

Case 3.

Next Songge through a simple case, and we demonstrate the specific implementation of the delay queue.

Start with a RabbitMQ startup.

Then we create a Spring Boot project to introduce RabbitMQ dependencies:

Then configure RabbitMQ’s basic connection information in application.properties:

spring.rabbitmq.host=localhost
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.port=5672
Copy the code

Next we configure two message queues: a normal queue and a dead letter queue:

@Configuration
public class QueueConfig {
    public static final String JAVABOY_QUEUE_NAME = "javaboy_queue_name";
    public static final String JAVABOY_EXCHANGE_NAME = "javaboy_exchange_name";
    public static final String JAVABOY_ROUTING_KEY = "javaboy_routing_key";
    public static final String DLX_QUEUE_NAME = "dlx_queue_name";
    public static final String DLX_EXCHANGE_NAME = "dlx_exchange_name";
    public static final String DLX_ROUTING_KEY = "dlx_routing_key";

    /** * dead letter queue *@return* /
    @Bean
    Queue dlxQueue(a) {
        return new Queue(DLX_QUEUE_NAME, true.false.false);
    }

    /** * dead letter switch *@return* /
    @Bean
    DirectExchange dlxExchange(a) {
        return new DirectExchange(DLX_EXCHANGE_NAME, true.false);
    }

    /** * Bind a dead letter queue to a dead letter switch *@return* /
    @Bean
    Binding dlxBinding(a) {
        return BindingBuilder.bind(dlxQueue()).to(dlxExchange())
                .with(DLX_ROUTING_KEY);
    }

    /** * Normal message queue *@return* /
    @Bean
    Queue javaboyQueue(a) {
        Map<String, Object> args = new HashMap<>();
        // Set the message expiration time
        args.put("x-message-ttl".1000*10);
        // Set a dead-letter switch
        args.put("x-dead-letter-exchange", DLX_EXCHANGE_NAME);
        // Set a dead letter routing_key
        args.put("x-dead-letter-routing-key", DLX_ROUTING_KEY);
        return new Queue(JAVABOY_QUEUE_NAME, true.false.false, args);
    }

    /** * Common switch *@return* /
    @Bean
    DirectExchange javaboyExchange(a) {
        return new DirectExchange(JAVABOY_EXCHANGE_NAME, true.false);
    }

    /** * Bind the normal queue to the corresponding switch *@return* /
    @Bean
    Binding javaboyBinding(a) {
        returnBindingBuilder.bind(javaboyQueue()) .to(javaboyExchange()) .with(JAVABOY_ROUTING_KEY); }}Copy the code

This configuration code is a bit longer, but the principle is simple.

  • The configuration can be divided into two groups. The first group is configured with a dead letter queue, and the second group is configured with a normal queue. Each group consists of message queues, message switches, and bindings.
  • When configuring a message queue, specify a dead letter queue for the message queue. Portal: Do messages in RabbitMQ expire? .
  • The default time unit for setting the expiration time of messages in a queue is milliseconds.

Next we configure a consumer for the dead-letter queue as follows:

@Component
public class DlxConsumer {
    private static final Logger logger = LoggerFactory.getLogger(DlxConsumer.class);

    @RabbitListener(queues = QueueConfig.DLX_QUEUE_NAME)
    public void handle(String msg) { logger.info(msg); }}Copy the code

Print out the message when you receive it.

That’s it.

Start the project.

Finally, we send a message in the unit test:

@SpringBootTest
class DelayQueueApplicationTests {

    @Autowired
    RabbitTemplate rabbitTemplate;

    @Test
    void contextLoads(a) {
        System.out.println(new Date());
        rabbitTemplate.convertAndSend(QueueConfig.JAVABOY_EXCHANGE_NAME, QueueConfig.JAVABOY_ROUTING_KEY, "hello javaboy!"); }}Copy the code

There is nothing more to be said for this, just a normal message is sent and 10 seconds later the message is printed out in the dead-letter queue of consumers.

4. Summary

So that’s the idea behind using RabbitMQ as a delay queue

Reply to the title of the article in the background of the official account, you can download the case of this article ~