Rabbitmq基于延迟插件实现延时

以前的项目实现延时功能,基于redis的过期机制 ,但是redis的弊端过于明显,后来改为rabbitmq的死信队列,今天有空改为了基于延迟插件。简单记录一下。

延迟插件的安装

rabbitmq的安装这里不再赘述,根据自己安装的Rabbitmq版本选择对应的延迟插件。https://rabbitmq.com/community-plugins.html

在这里插入图片描述

然后根据自己mq版本选择对应的插件
在这里插入图片描述

然后把插件放到安装目录的plugins下面,执行
rabbitmq-plugins enable rabbitmq_delayed_message_exchange

项目集成mq

简单的依赖引入 这里不再赘述,开启手动确认 确保准确被消费。


spring:
  rabbitmq:
    host: 服务器ip
    username: guest
    password: guest
    port: 5672
    virtual-host: /
    #开启确认机制
    publisher-confirm-type: correlated
    publisher-returns: true
    listener:
      simple:
        acknowledge-mode: manual
@Configuration
public class RabbitMqConfig {

    private final static Logger log = LoggerFactory.getLogger(RabbitMqConfig.class);
    //延迟交换机
    public static final String DELAY_EXCHANGE = "delay_exchange";
    //延迟队列
    public static final String DELAY_QUEUE = "delay_queue";
    //延迟路由键
    public static final String DELAY_QUEUE_ROUTING_KEY = "delay_queue_routing_key";

    @Autowired
    private CachingConnectionFactory cachingConnectionFactory;

    //队列
    @Bean
    public Queue delyqueue() {
        return new Queue(DELAY_QUEUE, true);
    }

    //交换机
    @Bean
    public DirectExchange delyExchange() {
        Map<String, Object> args = new HashMap<>();
        args.put("x-delayed-message", "direct");
        DirectExchange exchange = new DirectExchange(DELAY_EXCHANGE, true, false, args);
        exchange.setDelayed(true);
        return exchange;
    }


    //绑定
    @Bean
    public Binding delyBind() {
        return BindingBuilder.bind(delyqueue()).to(delyExchange()).with(DELAY_QUEUE_ROUTING_KEY);
    }



    @Bean
    RabbitTemplate rabbitTemplate() {
        RabbitTemplate rabbitTemplate = new RabbitTemplate(cachingConnectionFactory);
        //发送情况监控
        rabbitTemplate.setConfirmCallback((data, ack, cause) -> {
            String msgId = data.getId();
            System.out.println(data.toString());
            if (ack) {
                log.info("message发送成功" + msgId);
            } else {
                log.info("message发送失败" + msgId);
            }
        });
        //rabbit自身错误监控
        rabbitTemplate.setReturnCallback((msg, repCode, repText, exchange, routingkey) -> {
            log.info("Rabblimq自身原因邮件发送失败" + msg);
        });
        return rabbitTemplate;
    }

}



生产者,这里修改为把传递的标识放到自定义的header里面。自带提供的获取的时候会遇到为null的情况。

@Service
public class producerService {

    private final static Logger logger = LoggerFactory.getLogger(producerService.class);

    @Autowired
    private RabbitTemplate rabbitTemplate;


    public void sentDelyMsg(Integer delayTime, String message) {
        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
        logger.info("发送信息的标识为:" + uuid);
        logger.info("-------------开启延迟队列-------------");
        rabbitTemplate.convertAndSend("delay_exchange", "delay_queue_routing_key",
                message, msg -> {
                    //setDelay()的本质是对消息头设置 x-delay 参数,用来指定消息的延迟时间
                    msg.getMessageProperties().setDelay(delayTime);
                    //把CorrelationData里面的id放到MessageProperties里面
                    msg.getMessageProperties().setHeader("uuid", uuid);
                    return msg;
                }, new CorrelationData(uuid));
        logger.info("-------------延迟队列任务建立-------------");
    }

}

消费者,获取唯一标识的时候从header里面取即可

@Component
public class Receive {

    private final static Logger logger = LoggerFactory.getLogger(Receive.class);


    @RabbitListener(queues = "delay_queue")
    public void receiveMessage(Message message, Channel channel) throws Exception {
        long tag = message.getMessageProperties().getDeliveryTag();
        Object msgId = message.getMessageProperties().getHeaders().get("uuid");
        String msg = new String(message.getBody());
        logger.info("当前时间:{},从延迟队列中消费的消息:{}", LocalDateTime.now(), msg);
        try {
            //模拟出现异常
            int i = 5 / 0;
            channel.basicAck(tag, false);
            logger.info(msgId + ":消费成功");
        } catch (Exception e) {
            //拒绝签收
            //channel.basicNack(tag, false, true);
            logger.error(e.getMessage(), e);
            //然后把错误的信息  单独记录到错误的信息表里面
        } finally {
            channel.basicAck(tag, false);
            logger.info(msgId + ":消费成功");
        }
    }
}

结果展示

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值