refactor(mq-starter-core): 抽取 doFlush 统一批量刷出路径 + flushLock 串行化业务调用

为 idle flush 铺路:满批/超时/停机三路径将共用同一刷出段,失败语义只写一份。
flushLock 使业务批量方法任一时刻至多一个调用(rocketmq 端原有多满批并发刷
顺带收紧为串行,设计已确认)。行为对既有测试不变。

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-14 20:56:08 +08:00
parent ad864e5b93
commit 98731c3591

View File

@@ -25,6 +25,8 @@ public class MqConsumeDispatcher {
private final MqConsumeErrorHandler errorHandler;
private final MqBatchConsumer consumer;
private final List<MqMessage> buffer = new ArrayList<>();
/** 串行化三条刷出路径(满批/超时/停机)的业务调用段:业务批量方法任一时刻至多一个调用在跑。 */
private final Object flushLock = new Object();
private MqConsumeDispatcher(Builder b) {
this.batchSize = b.batchSize;
@@ -73,11 +75,21 @@ public class MqConsumeDispatcher {
}
}
if (flush != null) {
doFlush(flush);
}
}
/**
* 刷出一批:业务消费 → 成功逐条 markSuccess / 失败逐条 SINGLE 落库 + 吞。
* 满批 / 超时 / 停机三条路径都汇聚到这里,失败语义只写一份:
* 批量消息已逐条 ACK 无法精确重投整批 → 对齐 legacy 不卡队列:落库 + 吞掉,
* 不抛、不标 success去重 processing 标记自然过期)。
*/
private void doFlush(List<MqMessage> flush) {
synchronized (flushLock) {
try {
consumer.consume(flush);
} catch (Exception e) {
// 批量入库失败:消息已逐条 ACK无法精确重投整批 → 对齐 legacy 不卡队列:
// 落库 + 吞掉,不抛、不标 success去重 processing 标记自然过期)。
log.warn("[mq] 批量消费失败,已落库并放弃该批 {} 条", flush.size(), e);
for (MqMessage m : flush) {
safeOnError(m, MqErrorIdentity.SINGLE, e);