RabbitMQ实现延迟队列的两种方式

方法一:通过插件实现(好处:实现了,不阻塞的延迟队列)

  1.  先安装rabbitMQ延迟插件 ---> rabbitmq-delayed-message-exchange (高版本的rabbitMQ安装完插件之后无需重启)
    当出现添加交换机有如图所示的选项时,说明安装插件成功

  2.  定义常量
     

       /**
         * 访客延迟队列
         */
        String VISITOR_DELAY_QUEUE ="yxb.visitor.delay.queue";
    
        /**
         * 访客延迟交换机
         */
        String VISITOR_DELAY_EXCHANGE = "yxb.visitor.delay.exchange";
    
        /**
         * 访客延迟消息路由key
         */
        String VISITOR_DELAY_ROUTE_KEY = "yxb.receive.visitor.delay.routeKey";

  3. 创建延迟队列

    /**
         * 访客延迟队列
         * @return
         */
        @Bean
        Queue visitorDelayQueue() {
            return new Queue(MqConstant.VISITOR_DELAY_QUEUE);
        }

  4. 创建延迟交换机
     

    @Bean
        public CustomExchange visitorDelayExchange(){
            HashMap<String, Object> args = new HashMap<>();
            args.put("x-delayed-type","direct");
            return new CustomExchange(MqConstant.VISITOR_DELAY_EXCHANGE,"x-delayed-message",true,false,args);
        }

  5. 绑定延迟队列和交换机

       /**
         * 延迟队列绑定交换机
         * @param visitorDelayQueue 延迟队列
         * @param visitorDelayExchange 交换机
         * @return Binding
         */
        @Bean
        public Binding bindVisitorDelayExchange(@Qualifier("visitorDelayQueue") Queue visitorDelayQueue,
                                                @Qualifier("visitorDelayExchange") CustomExchange visitorDelayExchange){
            return BindingBuilder.bind(visitorDelayQueue).to(visitorDelayExchange).with(MqConstant.VISITOR_DELAY_ROUTE_KEY).noargs();
        }

  6. 发送延迟消息
     

      rabbitTemplate.convertAndSend(mqMessage.getExchange(),mqMessage.getRoutingKey(),mqMessage, message -> {
                    // 设置延迟毫秒值
                    message.getMessageProperties().setDelay(delayTimes.intValue());
                    return message;
                }, new CorrelationData(mqMessage.getId()));

  7. 监听延迟队列
     

    @Component
    @AllArgsConstructor
    @Slf4j
    public class VisitorEventDrive {
        private final VisitorOrdersService visitorOrdersService;
    
        @RabbitHandler
        @RabbitListener(queues = MqConstant.VISITOR_DELAY_QUEUE)
        public void receiveEvent(Message message, Channel channel, MqMessage mqMessage){
            try {
                //doSomething
            } catch (Exception e) {
                e.toString();
            }
        }
    }

方法二:通过死信实现延迟队列(不推荐,会存在阻塞的情况)

比如:先向队列中发送一个60秒到期的消息,再往队列中发送一个30秒到期的消息.预想的是队列先执行30秒的消息,再执行60秒的消息.但是实际情况是60秒的消息会阻塞队列,导致先执行了60秒的消息,再执行30秒的消息.(延迟30秒的要求没有实现)

  1. 创建死信队列和转发队列
    /**
         * 访客二维码死信队列
         * @return
         */
        @Bean
        Queue visitorTtlQueue() {
            return QueueBuilder
                    .durable(MqConstant.VISITOR_TTL_QUEUE)
                    // 配置到期后转发的交换
                    .withArgument("x-dead-letter-exchange", MqConstant.VISITOR_DIRECT_EXCHANGE)
                    // 配置到期后转发的路由键
                    .withArgument("x-dead-letter-routing-key", MqConstant.TTL_CHANGE_ROUTE_KEY)
                    .build();
        }
    
        /**
         * 访客二维码死信消息转发队列
         * @return 队列
         */
        @Bean
        public Queue visitorTtlChangeQueue(){
            return new Queue(MqConstant.VISITOR_TTL_CHANGE_QUEUE);
        }

  2. 创建直连交换机和延时交换机
    /**
         * 访客直连交换机
         * @return 交换机
         */
        @Bean
        public DirectExchange visitorDirectExchange(){
            return new DirectExchange(MqConstant.VISITOR_DIRECT_EXCHANGE);
        }
    
    
        /**
         * 延时消息交换机配置
         * @return DirectExchange
         */
        @Bean
        DirectExchange messageTtlDirect() {
            return (DirectExchange) ExchangeBuilder.directExchange(MqConstant.MESSAGE_TTL_EXCHANGE).durable(true).build();
        }

  3. 绑定队列和交换机
    
    
        /**
         * 死信队列绑定交换机
         * @param visitorTtlQueue 死信队列
         * @param messageTtlDirect 交换机
         * @return Binding
         */
        @Bean
        public Binding bindVisitorTtlDirectExchange(@Qualifier("visitorTtlQueue") Queue visitorTtlQueue,
                                                @Qualifier("messageTtlDirect") DirectExchange messageTtlDirect){
            return BindingBuilder.bind(visitorTtlQueue).to(messageTtlDirect).with(MqConstant.TTL_ROUTE_KEY);
        }
    
    
    /**
         * 转发队列绑定交换机
         * @param visitorTtlChangeQueue
         * @param visitorDirectExchange
         * @return Binding
         */
        @Bean
        public Binding bindVisitorTtlChangeExchange(@Qualifier("visitorTtlChangeQueue") Queue visitorTtlChangeQueue,
                                             @Qualifier("visitorDirectExchange") DirectExchange visitorDirectExchange){
            return BindingBuilder.bind(visitorTtlChangeQueue).to(visitorDirectExchange).with(MqConstant.TTL_CHANGE_ROUTE_KEY);
        }

  4. 发送死信消息
    rabbitTemplate.convertAndSend(mqMessage.getExchange(),mqMessage.getRoutingKey(),mqMessage, message -> {
                    // 设置延迟毫秒值
                    message.getMessageProperties().setExpiration(String.valueOf(delayTimes));
                    return message;
                }, new CorrelationData(mqMessage.getId()));

  5. 监听转发队列
    @Component
    @AllArgsConstructor
    @Slf4j
    public class VisitorEventDrive {
    
        @RabbitHandler
        @RabbitListener(queues = MqConstant.VISITOR_TTL_CHANGE_QUEUE)
        public void receiveEvent(Message message, Channel channel, MqMessage mqMessage){
            try {
               //doSomeThing
                
            }catch (Exception e) {
                
            }
        }
    }

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值