RabbitMQ is so simple to implement delay message that the whole plug-in is finished

There are two ways for RabbitMQ to implement delay messages, one is to use dead letter queue, the other is to use delay plug-in. We've talked about dead letter queue implementation before. This time, we'll talk about a simpler one, which is implemented with a delay plug-in.

Plug in installation

First we need to download and install RabbitMQ's delay plug-in.

  • Go to the official website of RabbitMQ to download the plug-in. The plug-in address is: https://www.rabbitmq.com/community-plugins.html
  • Search RabbitMQ directly_ delayed_ message_ Exchange can find the plug-in we need to download. Download the version matching RabbitMQ. Don't get it wrong;

 

  • Copy the plug-in file to the plugins directory of RabbitMQ installation directory;

 

  • Enter the sbin directory of RabbitMQ installation directory, and use the following command to enable the delay plug-in;
rabbitmq-plugins enable rabbitmq_delayed_message_exchange
  • After the plug-in is enabled successfully, you can see the following information, and then restart the RabbitMQ service.

 

Implementation delay message

Next, we need to implement the delay message function in spring boot. This time, we still use the scenario of ordering goods. For example, if a user places an order and doesn't pay for it within 60 minutes, the order will be cancelled. This is a typical delay message usage scenario.

  • First of all, we need to pom.xml Add AMQP related dependency in the document;
<!--Message queuing dependency-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
  • After that application.yml Add the relevant configuration of RabbitMQ;
spring:
  rabbitmq:
    host: localhost #Connection address of rabbitmq
    port: 5672 #Connection port number of rabbitmq
    virtual-host: /mall #Virtual host of rabbitmq
    username: mall #User name of rabbitmq
    password: mall #The password of rabbitmq
    publisher-confirms: true #If a callback is required for an asynchronous message, it must be set to true
  • Next, create the Java configuration of RabbitMQ, which is mainly used to configure switches, queues and binding relationships;
/**
 * Message queuing configuration
 * Created by macro on 2018/9/14.
 */
@Configuration
public class RabbitMqConfig {

    /**
     * Switch to which order delay plug-in message queuing is bound
     */
    @Bean
    CustomExchange  orderPluginDirect() {
        //Create a custom switch to send delay messages
        Map<String, Object> args = new HashMap<>();
        args.put("x-delayed-type", "direct");
        return new CustomExchange(QueueEnum.QUEUE_ORDER_PLUGIN_CANCEL.getExchange(), "x-delayed-message",true, false,args);
    }

    /**
     * Order delay plug in queue
     */
    @Bean
    public Queue orderPluginQueue() {
        return new Queue(QueueEnum.QUEUE_ORDER_PLUGIN_CANCEL.getName());
    }

    /**
     * Bind the order delay plug-in queue to the switch
     */
    @Bean
    public Binding orderPluginBinding(CustomExchange orderPluginDirect,Queue orderPluginQueue) {
        return BindingBuilder
                .bind(orderPluginQueue)
                .to(orderPluginDirect)
                .with(QueueEnum.QUEUE_ORDER_PLUGIN_CANCEL.getRouteKey())
                .noargs();
    }

}
  • Create a sender of cancel order message, set the delay time of message from switch to queue by setting x-delay header to the message;
/**
 * Sender of cancel order message
 * Created by macro on 2018/9/14.
 */
@Component
public class CancelOrderSender {
    private static Logger LOGGER =LoggerFactory.getLogger(CancelOrderSender.class);
    @Autowired
    private AmqpTemplate amqpTemplate;

    public void sendMessage(Long orderId,final long delayTimes){
        //Send message to delay queue
        amqpTemplate.convertAndSend(QueueEnum.QUEUE_ORDER_PLUGIN_CANCEL.getExchange(), QueueEnum.QUEUE_ORDER_PLUGIN_CANCEL.getRouteKey(), orderId, new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                //Set delay milliseconds for messages
                message.getMessageProperties().setHeader("x-delay",delayTimes);
                return message;
            }
        });
        LOGGER.info("send delay message orderId:{}",orderId);
    }
}
  • Create a receiver of the cancel order message to process the message in the order delay plug-in queue.
/**
 * Processor of cancel order message
 * Created by macro on 2018/9/14.
 */
@Component
@RabbitListener(queues = "mall.order.cancel.plugin")
public class CancelOrderReceiver {
    private static Logger LOGGER =LoggerFactory.getLogger(CancelOrderReceiver.class);
    @Autowired
    private OmsPortalOrderService portalOrderService;
    @RabbitHandler
    public void handle(Long orderId){
        LOGGER.info("receive delay message orderId:{}",orderId);
        portalOrderService.cancelOrder(orderId);
    }
}
  • Then add the following logic to our order business implementation class. Before the order is placed successfully, send a delay message to the message queue to cancel the order, so that if the order is not paid, the order can be cancelled;
/**
 * Front order management Service
 * Created by macro on 2018/8/30.
 */
@Service
public class OmsPortalOrderServiceImpl implements OmsPortalOrderService {
    private static Logger LOGGER = LoggerFactory.getLogger(OmsPortalOrderServiceImpl.class);
    @Autowired
    private CancelOrderSender cancelOrderSender;

    @Override
    public CommonResult generateOrder(OrderParam orderParam) {
        //todo performs a series of single operations, refer to the mall project for details
        LOGGER.info("process generateOrder");
        //Open a delay message after the order is completed, which is used to cancel the order when the user does not pay (orderId should be generated after the order is placed)
        sendDelayMessageCancelOrder(11L);
        return CommonResult.success(null, "checkout success ");
    }

    @Override
    public void cancelOrder(Long orderId) {
        //todo performs a series of order cancellation operations. Please refer to the mall project for details
        LOGGER.info("process cancelOrder orderId:{}",orderId);
    }

    private void sendDelayMessageCancelOrder(Long orderId) {
        //Get order timeout, assuming 60 minutes (30 seconds for testing)
        long delayTimes = 30 * 1000;
        //Send delay message
        cancelOrderSender.sendMessage(orderId, delayTimes);
    }

}
  • After launching the project, the next interface is called in Swagger.

 

  • After the call is completed, you can check the console log and find that the difference between message sending and message receiving is exactly 30s. We set the delay time.
2020-06-08 13:46:01.474  INFO 1644 --- [nio-8080-exec-1] c.m.m.t.s.i.OmsPortalOrderServiceImpl    : process generateOrder
2020-06-08 13:46:01.482  INFO 1644 --- [nio-8080-exec-1] c.m.m.tiny.component.CancelOrderSender   : send delay message orderId:11
2020-06-08 13:46:31.517  INFO 1644 --- [cTaskExecutor-4] c.m.m.t.component.CancelOrderReceiver    : receive delay message orderId:11
2020-06-08 13:46:31.520  INFO 1644 --- [cTaskExecutor-4] c.m.m.t.s.i.OmsPortalOrderServiceImpl    : process cancelOrder orderId:11

Comparison of two implementation methods

We have used the dead letter queue before. Here we compare the two methods. Let's talk about the implementation principle of the two methods.

Dead letter queue

Dead letter queue is such a queue. If a message is sent to the queue and exceeds the set time, it will be forwarded to the set queue for processing timeout messages. With this feature, delay messages can be realized.

Delay plug in

By installing plug-ins and customizing the switch, the switch has the ability to delay sending messages, thus realizing the delay messages.

conclusion

Because the dead letter queue mode needs to create two switches (dead letter queue switch + processing queue switch), two queues (dead letter queue + processing queue), and the delay plug-in mode only needs to create one switch and one queue, so the latter is easier to use.

Project source address

Forward + pay attention, and then I can get the free way of [project source code address] by private letter with the keyword "project"!

Recommended reading:

Horse soldier education 2020 the latest full version of horse soldier high concurrent multi thread 450 minute tutorial, [from entry to mastery]

The interview team was tortured by the JVM? Alibaba P9 architect takes 500 minutes to talk about JVM from introduction to actual combat

Hard core! Tsinghua double giant horse soldier VS Zhou Zhilei made it clear about TCP protocol, high concurrent load balancing, multithreading and the bottom layer of JVM

Should forty year old Java programmers be eliminated? Horse soldier's advice to all Java programmers, telling the secrets of modern students entering large factories

Tags: RabbitMQ Spring Java jvm

Posted on Wed, 17 Jun 2020 01:25:03 -0400 by dmarquard