RabbitMQ dead letter queue method of payment timeout order closing policy

catalogue

1, Why is there an overtime customs clearance in the demand background

2, So most order businesses have this function. How to design it?

3, RabbitMQ dead letter queue - review of knowledge points of delayed messages

3.1 what is rabbitmq's dead letter queue

3.2 what is rabbitmq's dead letter switch

3.3 what kinds of situations can a message become a dead letter

3.4 what is a delay queue

4, Code link

4.1 Rabbitmq dead letter queue configuration

4.2 sending of delayed messages

4.3 customer processing of customs declaration

1, Why is there an overtime customs clearance in the demand background

Reason 1: the payment connection of the third-party payment platform is time sensitive. After the order is created, the payment needs to be completed within a certain time
WeChat payment, Alipay payment, etc.
You can also make secondary payment without closing the order, but the business link will be more complex
Reason 2: the e-commerce business will also involve the locking and release of commodity inventory

2, So most order businesses have this function. How to design it?

3, RabbitMQ dead letter queue - review of knowledge points of delayed messages

3.1 what is RabbitMQ's dead letter queue

A queue in which messages that are not consumed in time are stored

3.2 what is rabbitmq's dead letter switch

Dead letter exchange (DLX) when a message becomes a dead letter, it will be re sent to another switch, which is the DLX dead letter switch

3.3 what kinds of situations can a message become a dead letter

The consumer does not re queue the message (request. Basic / request = false)
The message is not consumed in the queue and exceeds the expiration time TTL (time to live) of the queue or the message itself
The message length of the queue has reached its limit
Result: after the message becomes a dead letter, if the queue is bound to the dead letter switch, the message will be rerouted to the dead letter queue by the dead letter switch

3.4 what is a delay queue

A message queue with delay function. Producer sends a message to the message queue server, but does not expect the message to be delivered immediately. Instead, it delays the message to be delivered to the Consumer for consumption at a certain time after the current time point. The message is a timed message
Some implementation methods in the industry:
           . Timed task high-precision rotation training
           . redis listening key expired
           . DelayQueue of jdk
           . RocketMQ's built-in delay message function is adopted
           . RabbitMQ itself does not support delay queue. Combined with the characteristics of dead letter queue, you can delay messages

4, Link code

4.1 Rabbitmq dead letter queue configuration

package net.wnn.config;

import lombok.Data;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.Exchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.Map;

/**
 *  * Customize message queuing configuration,
 *  * Send customs clearance message - delay exchange - order close. delay. Queue - "dead letter exchange -" order close. queue
 **/

@Configuration
@Data
public class RabbitMQConfig {
    /**
     * Switch
     */
    private String orderEventExchange="order.event.exchange";
    /**
     * Delayed queue, which cannot be monitored by consumers
     */
    private String orderCloseDelayQueue = "order.close.delay.queue";
    /**
     * The customs clearance queue is a queue for forwarding messages after expiration, which is used to be monitored by consumers
     */
    private String orderCloseQueue = "order.close.queue";
    /**
     * routingKey entering delay queue
     */
    private String orderCloseDelayRoutingKey = "order.close.delay.routing.key";
    /**
     * The routingKey that enters the dead letter queue, and the key that enters the dead letter queue when the message expires
     */
    private String orderCloseRoutingKey = "order.close.routing.key";
    /**
     * Expiration time, in milliseconds, temporarily changed to 1 minute
     */
    private Integer ttl = 1000 * 60;
    /**
     * Message converter
     * @return
     */
    @Bean
    public MessageConverter messageConverter(){
        return new Jackson2JsonMessageConverter();
    }
    /**
     * Create a switch, topic type, generally one switch for one service
     * @return
     */
    @Bean
    public Exchange orderEventExchange(){
        return new TopicExchange(orderEventExchange,true,false);
    }
    /**
     * Delay queue getOrderEventExchange
     * @return
     */
    @Bean
    public Queue orderCloseDelayQueue(){
        Map<String,Object> args = new HashMap<>(3);
        args.put("x-dead-letter-exchange",orderEventExchange);
        args.put("x-dead-letter-routing-key",orderCloseRoutingKey);
        args.put("x-message-ttl",ttl);
        return new Queue(orderCloseDelayQueue,true,false,false,args);

    }
    /**
     * Dead letter queue is an ordinary queue used to be monitored
     * @return
     */
    @Bean
    public Queue orderCloseQueue(){
        return new Queue(orderCloseQueue,true,false,false);
    }
    /**
     * The first queue, the delay queue, establishes a binding relationship with the switch
     * @return
     */
    @Bean
    public Binding orderCloseDelayBinding(){
        return new Binding(orderCloseDelayQueue,
                Binding.DestinationType.QUEUE,orderEventExchange,orderCloseDelayRoutingKey,null);
    }
    /**
     * The dead letter queue establishes a binding relationship with the dead letter switch
     * @return
     */
    @Bean
    public Binding orderCloseBinding(){

        return new Binding(orderCloseQueue,
                Binding.DestinationType.QUEUE,orderEventExchange,orderCloseRoutingKey,null);
    }


}
##----------rabbit configuration--------------
spring.rabbitmq.host=120.79.xxx.xxx
spring.rabbitmq.port=5672
#The virtual host needs to be created manually
spring.rabbitmq.virtual-host=dev
spring.rabbitmq.username=admin
spring.rabbitmq.password=password
#Message confirmation mode, manual (manual ack) and auto (automatic ack); The message consumption retries reach the specified number of times and enter the exception switch and exception queue. It needs to be changed to automatic ack confirmation message
spring.rabbitmq.listener.simple.acknowledge-mode=auto

 

4.2 sending of delayed messages

    @Autowired
    private RabbitMQConfig rabbitMQConfig;
    @Autowired
    private RabbitTemplate rabbitTemplate;
 
//Send delay message
            EventMessage eventMessage = EventMessage.builder()
                .eventMessageType(EventMessageType.PRODUCT_ORDER_NEW.name())
                .accountNo(loginUser.getAccountNo())
                .bizId(orderOutTradeNo)
                .build();

        rabbitTemplate.convertAndSend(rabbitMQConfig.getOrderEventExchange(),rabbitMQConfig.getOrderCloseDelayRoutingKey(),eventMessage);

4.3 customer processing of customs declaration

package net.wnn.listener;

import com.rabbitmq.client.Channel;
import lombok.extern.slf4j.Slf4j;
import net.wnn.enums.BizCodeEnum;
import net.wnn.exception.BizException;
import net.wnn.model.EventMessage;
import net.wnn.service.ProductOrderService;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
@Slf4j
@RabbitListener(queuesToDeclare = {@Queue("order.close.queue")})
public class ProductOrderMQListener {

    @Autowired
    private ProductOrderService productOrderService;

    @RabbitHandler
    public void productOrderHandler(EventMessage eventMessage, Message message, Channel channel){
        log.info("Listen to the message ProductOrderMQListener messsage Message content:{}",message);
        try{
            //Close order business logic
            productOrderService.closeProductOrder(eventMessage);
        }catch (Exception e){
            log.error("Consumer failure:{}",eventMessage);
            throw new BizException(BizCodeEnum.MQ_CONSUME_EXCEPTION);
        }
        log.info("Consumption success:{}",eventMessage);
    }
}

After listening to the delayed closing message, query the order and payment according to the actual business to determine whether to perform the closing operation

Keywords: RabbitMQ

Added by s1yman on Fri, 11 Feb 2022 04:44:12 +0200