当前位置: 首页 > ops >正文

rabbitmq学习笔记 ----- 多级消息延迟始终为 20s 问题排查

问题现象

在实现多级延迟消息功能时,发现每次消息延迟间隔始终为20s,无法按照预期依次使用20s→10s→5s的延迟时间。日志显示每次处理时移除的延迟时间都是20000L。

问题代码片段

1.生产者

@Testvoid sendDelayMessage2() {List<Long> expireTimeList = new ArrayList<>();{expireTimeList.add(20000L);expireTimeList.add(10000L);expireTimeList.add(5000L);}delayMessage<String> msg = new delayMessage<>("hello,world222!", expireTimeList);rabbitTemplate.convertAndSend("delay.exchange", "hi",msg, message -> {message.getMessageProperties().setDelay(msg.removeDelayTime().intValue());return message;});}

2.消费者

    @RabbitListener(bindings = @QueueBinding(value = @Queue(value = "delay.queue", durable = "true"),exchange = @Exchange(value = "delay.exchange", delayed = "true"),key = "hi"))public void listenMultiDelay(delayMessage<String> msg) {log.info("收到消息: {}" , msg.getMessage());if(msg.hasExpireTime()){log.info("消息还有延迟时间,继续投递,剩余延迟时间:" );rabbitTemplate.convertAndSend("delay.exchange", "hi",msg, message -> {message.getMessageProperties().setDelay(msg.removeDelayTime().intValue());return message;});}}

3.延迟消息类

@Data
public class delayMessage<T> {private T message;private List<Long> expireTime;public delayMessage() {}public delayMessage(T message, List<Long> expireTime) {this.message = message;this.expireTime = expireTime;}public Long removeDelayTime(){System.out.println("removeDelayTime: "+expireTime.get(0));return expireTime.remove(0);}public boolean hasExpireTime(){return !expireTime.isEmpty();}}

4.启动配置

    @Beanpublic MessageConverter messageConverter() {return new Jackson2JsonMessageConverter();}

核心原因分析

问题根源Jackson2JsonMessageConverter的序列化特性与业务逻辑设计之间的冲突有关:

  • Jackson2JsonMessageConverter工作机制

    • 发送消息时,将对象序列化为JSON字符串(数据快照)
    • 接收消息时,将JSON字符串重新反序列化为全新的对象实例,而非复用原对象
  • 对delayMessage对象的影响

    • 发送端调用removeDelayTime()后,内存中对象的expireTime列表已变为[10000L, 5000L]
    • 但序列化保存的是操作前的状态快照(包含20000L的完整列表)
    • 消费者接收时,反序列化创建的是新对象,expireTime列表恢复为初始状态[20000L, 10000L, 5000L]
    • 导致每次处理都从20000L开始,形成无限循环
  • 总结:说人话就是 Jackson2JsonMessageConverter 将消息转换成json格式前,delayMessage中的expireTime还没有收到removeDelayTime()的影响而改变

解决方案: 先改对象,再序列化

修正后代码:生产者(消费者同理)

    @Testvoid sendDelayMessage2() {List<Long> expireTimeList = new ArrayList<>();{expireTimeList.add(20000L);expireTimeList.add(10000L);expireTimeList.add(5000L);}delayMessage<String> msg = new delayMessage<>("hello,world222!",expireTimeList);// 先进行延迟时间的更新Long delaytime = msg.removeDelayTime();rabbitTemplate.convertAndSend("delay.exchange", "hi",msg, message -> {message.getMessageProperties().setDelay(delaytime.intValue());return message;});}

通过以上调整,多级延迟消息可按预期依次使用20s→10s→5s的延迟时间,最终解决了始终20s延迟的问题。

http://www.xdnf.cn/news/18965.html

相关文章:

  • 2025最新uni-app横屏适配方案:微信小程序全平台兼容实战
  • Java开发MongoDB常见面试题及答案
  • DQL单表查询相关函数
  • 【WPF】WPF 自定义控件实战:从零打造一个可复用的 StatusIconTextButton (含避坑指南)
  • 安卓开发---BaseAdapter(定制ListView的界面)
  • 中文PDF解析工具测评与选型指南
  • js AbortController 实现中断接口请求
  • 【面试场景题】三阶段事务提交比两阶段事务提交的优势是什么
  • 《C++进阶之STL》【AVL树】
  • 基于 GPT-OSS 的成人自考口语评测 API 开发全记录
  • 数据分析编程第七步:分析与预测
  • Qt节点编辑器设计与实现:动态编辑与任务流可视化(一)
  • 【拍摄学习记录】07-影调、直方图量化、向右向左
  • 经典扫雷游戏实现:从零构建HTML5扫雷游戏
  • 【Python】Python 实现 PNG 转 ICO 图标转换工具
  • LightGBM 在金融逾期天数预测任务中的经验总结
  • Qt自定义聊天消息控件ChatMessage:初步实现仿微信聊天界面
  • Linux之Shell编程(一)
  • Linux笔记12——shell编程基础-6
  • Swift 解法详解 LeetCode 365:水壶问题
  • Java -- 文件基础知识--Java IO流原理--FileReader
  • 了解ADS中信号和电源完整性的S参数因果关系
  • hintcon2025 Verilog OJ
  • 【python】python进阶——生成器
  • 数据结构01:顺序表
  • 次元小镇官网入口 - 二次元动漫社区|COS绘画插画壁纸分享
  • [数据结构] ArrayList与顺序表(下)
  • STM32——PWR
  • 机器视觉学习-day06-图像旋转
  • KafKa学习笔记