RabbitMQ-死信队列

发布时间 2024-01-05 11:16:40作者: 杨欢喜e

一、什么是死信队列

rabbitmq.com/dlx.html
死信交换机绑定的队列就叫死信队列。什么叫死信交换机?接收死信消息的交换机叫做死信交换机。什么叫做死信消息?

  1. 消息被拒绝,又没有重新入队的消息(basic.nack | basic.reject & requeue = false)
  2. 消息过期
  3. 队列达到最大长度后来的消息

其实,死信队列就是一个专门用来处理死信消息的普通队列,而死信交换机也只是一个用来接收死信消息的普通交换机。它们都没有特殊的地方。

二、应用场景

死信队列主要用来实现延时任务。

  • 订单超时取消支付
  • 红包失效
  • 7天自动确认收货

三、实现原理

业务消息放到一个普通队列A中,队列A不要有消费者,设置队列A的过期时间及绑定的死信队列,当消息过期后,会被投送到死信队列B中,监听队列B的消息进行处理。

四、实战

/**
     * 订单交换机
     * @return
     */
    @Bean
    public TopicExchange orderExchange(){
        return new TopicExchange(MQConstant.ORDER_EXCHANGE);
    }

    /**
     * 死信队列【一个普通队列】
     */
    @Bean
    public Queue dlQueue(){
        return new Queue(MQConstant.ORDER_DL_QUEUE, true, false, false);
    }

    /**
     * 延迟队列【不被监听】
     * @return
     */
    @Bean
    public Queue orderQueue(){
        // 10s 消息未消费 -> 进入死信队列
        Map<String, Object> args = new HashMap<>();
        args.put(MQConstant.DLE, MQConstant.ORDER_EXCHANGE);
        args.put(MQConstant.DLK, MQConstant.CANCEL_DL_ROUTE_KEY);
        args.put(MQConstant.TTL, 10000);
        return new Queue(MQConstant.ORDER_CREATE_QUEUE, true, false, false, args);
    }
/**
     * 死信队列绑定到交换机
     * @return
     */
    @Bean
    public Binding bindDl(){
        return BindingBuilder
                .bind(dlQueue())
                .to(orderExchange())
                .with(MQConstant.CANCEL_DL_ROUTE_KEY)
                ;
    }

    /**
     * 延迟队列绑定到交换机
     */
    @Bean
    public Binding bindDelayQueue(){
        return BindingBuilder
                .bind(orderQueue())
                .to(orderExchange())
                .with(MQConstant.ORDER_ROUTE_KEY);
    }

消费者,监听死信队列

@Component
public class OrderCancelReceiver {

    @RabbitListener(queues = {MQConstant.ORDER_DL_QUEUE})
    public void cancelOrder(Message message, Channel channel) throws IOException {
        System.out.println(new String (message.getBody()));
        System.out.println(new Date());

        channel.basicAck(message.getMessageProperties().getDeliveryTag(), true);
    }
}