docs(kdoc): 重写信箱生命周期相关 KDoc,改为直白说明并去掉内部编号
原有注释大量引用 §5.1/§5.2/Q2/US-01 这类文档编号和内部简称,跳过了"这段代码在做什么、 为什么这么做",没有读过设计文档的人基本读不懂。本次统一改成先讲清这件事本身、 再说为什么要这样做,编号只在末尾留一处指路。 覆盖本次改动涉及的 24 个 Kotlin 文件(生产 16 个 + 测试 8 个): - 领域与端口:ProcState(补齐全量字段说明与状态/错误分类逐项注释)、 ProcStateRepository / InboxCursorRepository / CminmsgInboxRepository 及 MailboxRow / BackfillDue / Backlog; - 收报:InboxPoller(把"水位连续、遇缺口停下、缺口老化"用大白话讲透)、 InboxService、JdbcCminmsgInboxRepository; - 处理:Pump / MessageProcessor、ScheduleProcessor、DynamicProcessors、 ProcFailure、JdbcProcStateRepository 与游标实现; - 回填与观测:BackfillService、InboxLifecycleHealthIndicator、JobRunner; - 配置与 stub:PipelineProps(三个新增参数说清取值理由)、MailboxProps、 StubRepositories; - 测试:8 个测试类改为"这些用例在守哪几条规矩",并保留 H2 不覆盖 ON CONFLICT 的说明。 术语统一按第一次出现就地解释:水位、处理标记、回填、死信、队头、终态。 纯注释改动;除拆分枚举时按仓库风格补的两个行尾逗号外无代码变更 (已用剥离注释后比对 HEAD 的方式逐文件核对)。测试仍为 78 passed / 1 skipped。
This commit is contained in:
@@ -19,11 +19,16 @@ import java.time.Duration
|
||||
import java.time.Instant
|
||||
|
||||
/**
|
||||
* 处理主泵(docs/flight-state.md §1 严格有序 + §4 处理事务与失败规则):
|
||||
* 单活动主泵严格 FIFO + HOL 阻塞 + 队头滞留转 DEAD。
|
||||
* 处理主泵:一个线程按消息 ID 从小到大一条条处理,保证先来的先处理。
|
||||
*
|
||||
* 终态与业务写入在处理器事务内原子提交;本泵只负责调度、边界化失败迁移与
|
||||
* 提交后的最佳努力回填(message-lifecycle §3/§4)。
|
||||
* 每次 tick 只看当前最小的未完成消息("队头"):
|
||||
* - 没有待处理消息就睡一个轮询间隔;
|
||||
* - 队头失败了还在退避期,就等到能重试的时刻;如果重试次数用尽或滞留太久,
|
||||
* 直接转死信,不放任它一直堵着;
|
||||
* - 其余情况交给 [MessageProcessor] 处理。
|
||||
*
|
||||
* 一次只处理一条是刻意的。后面的消息不能越过卡住的队头,否则同一条航班的报文
|
||||
* 可能被乱序应用,几十秒后才到的旧报文会把新状态覆盖回去。
|
||||
*/
|
||||
@Singleton
|
||||
class Pump(
|
||||
@@ -38,7 +43,7 @@ class Pump(
|
||||
@Volatile
|
||||
private var running = true
|
||||
|
||||
/** 优雅停机:loop 在当前 tick 收尾后退出;线程中断由 PipelineLifecycle 负责。 */
|
||||
/** 请求停机:当前 tick 跑完就退出。线程中断由 PipelineLifecycle 负责。 */
|
||||
fun stop() {
|
||||
running = false
|
||||
}
|
||||
@@ -51,7 +56,7 @@ class Pump(
|
||||
Thread.currentThread().interrupt()
|
||||
return
|
||||
} catch (e: Exception) {
|
||||
// 最后防线:失败状态迁移已在 processOne 边界内完成;致命 Error 不捕获
|
||||
// 兜底:单条消息的失败状态已在 processOne 内记录,这里只避免线程退出
|
||||
sleepQuietly(props.pipeline.pollInterval)
|
||||
}
|
||||
}
|
||||
@@ -74,7 +79,7 @@ class Pump(
|
||||
} else {
|
||||
sleepQuietly(Duration.between(clock.instant(), head.nextAttemptAt))
|
||||
}
|
||||
// PENDING、或 FAILED 退避已到期:交处理入口(内部有边界化失败迁移与 attempts 守卫)
|
||||
// 其余情况(新消息,或退避到期的重试)交给处理入口
|
||||
else -> processor.processOne(head)
|
||||
}
|
||||
}
|
||||
@@ -89,9 +94,13 @@ class Pump(
|
||||
}
|
||||
|
||||
/**
|
||||
* processOne:解码 → 绑定 → 处理器(事务内决策 + 落库 + 终态 + 回填意图)→ 提交后最佳努力回填。
|
||||
* 边界化失败迁移(ProcFailure):任何意外异常归于本条 head,FAILED(INFRA)+退避,不穿出杀泵;
|
||||
* MALFORMED / PROTOCOL 直接 DEAD 不重试(docs/design.md §2.3 错误分类)。
|
||||
* 处理一条消息:读原文 → 解码 → 绑定业务身份 → 分派给对应处理器 → 提交后回填标记。
|
||||
*
|
||||
* 业务数据和终态由各处理器在自己的事务里写入。终态一旦落下(成功、跳过或死信),
|
||||
* 这里马上试一次把处理标记写回信箱;写不进去也没关系,回填扫描会按退避继续重试。
|
||||
*
|
||||
* 任何意外异常都算在当前这条消息头上(记 FAILED(INFRA) 后重试),不会把主泵线程带崩。
|
||||
* 报文非法和整包协议拒绝不重试,直接进死信等人工处置。
|
||||
*/
|
||||
@Singleton
|
||||
class MessageProcessor(
|
||||
@@ -126,7 +135,7 @@ class MessageProcessor(
|
||||
}
|
||||
}
|
||||
|
||||
/** @return 是否已达终态(终态才允许回填信箱标记) */
|
||||
/** @return 这条消息是否已经落到终态(只有终态才允许回填信箱标记) */
|
||||
private fun processInternal(head: ProcState): Boolean {
|
||||
// 守卫:手工/遗留 FAILED 行若 attempts 已达上限,直接终态(防止退避到期后无限重试)
|
||||
if (head.state == ProcStatus.FAILED && procFailure.scheduler.exhausted(head.attempts)) {
|
||||
|
||||
Reference in New Issue
Block a user