e660afe2a2553b74fa2d5fa21ff8970474e4e214
tryAcquire 返回 false 的两类跳过此前一律静默 return,导致 driver 无差别 ACK: 消费者在 markSuccess/markFail 前崩溃残留的 processing 标记,会被当成"已处理" 而 ACK,该消息从未成功消费却被丢弃(Critical 静默丢消息)。 - MqIdempotentStore 新增 isCompleted(key),默认 true 保持旧行为,状态机实现须覆写 - MqConsumeDispatcher:跳过时按 isCompleted 分流——success 正常 return 让 driver ACK; 仍 processing 则抛 MqMessageInProgressException(新,纯控制流信号、不带栈)让 driver 不 ACK - RedisMqIdempotentStore.isCompleted 仅 success 视为完成;RedisStreamMqDriver 捕获信号异常时留 PEL 待重投 - 补 dispatcher 两类跳过 + store isCompleted 语义单测 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
mq-starter — 统一 MQ 抽象层("MQ 界的 JDBC")
一个独立、全平台通用的 starter。业务配一行 mq.type 选底层(rocketmq | redis-stream),
只面向 starter 接口编程,不关心用哪个 MQ、不管理生产者消费者;换 MQ = 改配置,业务代码一行不动。
- 坐标 groupId:
com.njcn,版本1.0.0-SNAPSHOT(Phase 2 阶段本地mvn install) - JDK 1.8 / Spring Boot 2.3.12.RELEASE /
META-INF/spring.factories自动装配 - 零业务依赖:不依赖
message-api等任何业务模块
业务视角(对外契约)
mq:
type: redis-stream # 或 rocketmq
// 发
@Resource MqTemplate mq;
mq.send("LN_Topic", payload);
mq.send("File_Topic", nodeId, payload); // 带路由 key
// 收(业务方法打注解,零 MQ 概念)
@MqListener(topic = "LN_Topic", group = "ln_consumer")
public void onFrontData(FrontData msg) { /* 纯业务 */ }
模块结构
| 模块 | 职责 |
|---|---|
mq-starter-core |
门面 MqTemplate + @MqListener 注解扫描 + 中立信封 MqMessage + driver SPI + 生命周期 |
mq-starter-rocketmq |
rocket driver(基于官方 rocketmq-spring 编程式注册) |
mq-starter-redis-stream |
redis driver(复用 redis-stream-springboot-starter 低层件,零改动 Phase 1) |
mq-spring-boot-starter |
聚合 jar,业务方只引这一个坐标 |
装配机制
@ConditionalOnProperty("mq.type") 静态二选一:两套 driver 各只在对应值下装配,
同一上下文只存在一个 MqDriver bean。
关联设计
- 设计稿:
cn-data-platform/docs/superpowers/specs/2026-06-25-mq-starter-design.md - 能力清单与轻量版范围:
cn-data-platform/docs/2026-06-25-mq-starter能力清单与轻量版范围.html - 实现计划(轻量版 Phase 2):
cn-data-platform/docs/superpowers/plans/2026-06-25-mq-starter-轻量版-phase2.md
Description
Languages
Java
100%