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
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