RabbitMQ延时队列实现订单关闭

  • 场景
    订单30分钟未支付,系统自动关闭有哪些实现方案?
    1.基于任务调度实现;
    2.基于redis过期key实现;
    3.基于redis延迟队列;
    4.基于MQ的延迟队列;
  • 本次使用RabbitMQ实现一个小demo
    原理:我们在下单后,往MQ投递一个消息,设置其有效期为30分钟,在不设置对应队列的消费者的情况下,该消息将一直不被消费,那么30分钟后,该消息过期会被投递到死信队列,由死信消费者消费,我们就可以在死信消费者根据订单id执行相应的业务逻辑。
  • application.properties中MQ的配置
#配置virtual-host虚拟主机
spring.rabbitmq.virtual-host=test_order_close
#ip地址
spring.rabbitmq.host=127.0.0.1
#用户名  密码
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
#连接端口号
spring.rabbitmq.port=5672

#死信队列
test.dlx.exchange=test_order_dlx_exchange
test.dlx.queue=test_order_dlx_queue
test.dlx.routingKey=dlx

##备胎交换机
test.order.exchange=test_order_exchange
test.order.queue=test_order_queue
test.order.routingKey=test.order
  • 死信的config类
@Component
public class DeadLetterMQConfig {

    /**
     * 订单交换机
     */
    @Value("${test.order.exchange}")
    private String orderExchange;

    /**
     * 订单队列
     */
    @Value("${test.order.queue}")
    private String orderQueue;

    /**
     * 订单路由key
     */
    @Value("${test.order.routingKey}")
    private String orderRoutingKey;

    /**
     * 死信交换机
     */
    @Value("${test.dlx.exchange}")
    private String dlxExchange;

    /**
     * 死信队列
     */
    @Value("${test.dlx.queue}")
    private String dlxQueue;
    /**
     * 死信路由
     */
    @Value("${test.dlx.routingKey}")
    private String dlxRoutingKey;

    /**
     * 声明死信交换机
     */
    @Bean
    public DirectExchange dlxExchange() {
        return new DirectExchange(dlxExchange);
    }

    /**
     * 声明死信队列
     */
    @Bean
    public Queue dlxQueue() {
        return new Queue(dlxQueue);
    }

    /**
     * 声明订单业务交换机
     */
    @Bean
    public DirectExchange orderExchange() {
        return new DirectExchange(orderExchange);
    }

    /**
     * 声明订单队列 核心操作一
     */
    @Bean
    public Queue orderQueue() {
        Map<String, Object> arguments = new HashMap<>(2);
        // 绑定我们的死信交换机
        arguments.put("x-dead-letter-exchange", dlxExchange);
        // 绑定我们的路由key
        arguments.put("x-dead-letter-routing-key", dlxRoutingKey);
        return new Queue(orderQueue, true, false, false, arguments);
    }

    /**
     * 绑定订单队列到订单交换机
     */
    @Bean
    public Binding orderBinding() {
        return BindingBuilder.bind(orderQueue()).to(orderExchange()).with(orderRoutingKey);
    }

    /**
     * 绑定死信队列到死信交换机
     */
    @Bean
    public Binding binding() {
        return BindingBuilder.bind(dlxQueue()).to(dlxExchange()).with(dlxRoutingKey);
    }
}

  • 测试controller
    @GetMapping("/addOrder")
    public String addOrder(){
        String orderId=System.currentTimeMillis()+"";
        OrderEntity orderEntity=new OrderEntity("订单过期测试",orderId,0);
        int result= orderMapper.addOrder(orderEntity);
        if(result<=0){
            return "fail";
        }
        rabbitTemplate.convertAndSend(orderExchange,orderRoutingKey,orderId,messagePostProcessor());
        return "success";
    }

    //处理待发送消息
    private MessagePostProcessor messagePostProcessor(){
        return  new MessagePostProcessor() {
            @Override
            public Message postProcessMessage(Message message) throws AmqpException {
                //设置有效期20秒
                message.getMessageProperties().setExpiration("20000");
                return message;
            }
        };
    }
  • 死信消费者
@Component
public class OrderDlxConsumer {

    @Autowired
    private OrderMapper orderMapper;

    //监听死信队列
    @RabbitListener(queues = "test_order_dlx_queue")
    public void orderConsumer(String orderId) {
        System.out.println("死信队列获取消息:" + orderId);
        if (StringUtils.isEmpty(orderId)) {
            return;
        }
        //根据id查询
        OrderEntity orderEntity = orderMapper.getOrder(orderId);
        if (null == orderEntity) {
            return;
        }
        //获取状态
        Integer orderStatus=orderEntity.getOrderStatus();
        //判断未支付 , 关闭订单
        if(0==orderStatus){
            orderMapper.updateStatus(orderId,2);
        }
    }
}
  • 测试
    配置虚拟消息服务器
    RabbitMQ延时队列实现订单关闭_第1张图片
    接口测试工具调用我们写的controller方法
    RabbitMQ延时队列实现订单关闭_第2张图片
    新增成功后数据库表中会新增一条status为0的记录
    在这里插入图片描述
    过期时间到了之后会执行死信消费者的方法
    RabbitMQ延时队列实现订单关闭_第3张图片
    然后执行对应的业务逻辑修改订单的status
    在这里插入图片描述
  • 文末附一个关于死信队列的博客,学习学习。
    【RabbitMQ】一文带你搞定RabbitMQ死信队列

你可能感兴趣的:(RabbitMQ延时队列实现订单关闭)