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:
@@ -3,32 +3,72 @@ package com.gzzn.omms.msgexchange.domain
|
||||
import java.time.Instant
|
||||
|
||||
/**
|
||||
* PROC_STATE 处理伴生状态(docs/design.md §2.1/§2.3):每消息一行,
|
||||
* MSG_ID = 信箱 ID 主键防重复入队;IDENTITY_KEY 唯一约束防业务重复;
|
||||
* 处理状态机与错误分类同设计文档 §2.3。SUCCEEDED 终态兼作 SCHD 快照
|
||||
* 重放判定(docs/flight-state.md §4 步骤 / design.md §4.1)。
|
||||
* 一条入站消息的处理记录,一行对应共享信箱 CMINMSGS 里的一条报文。
|
||||
*
|
||||
* 回填事实(message-lifecycle.md §5.2/§11)与处理事实同体同行:终态与回填意图
|
||||
* 由同一条 UPDATE 落下,因此不存在"业务已提交、回填待办未记"的崩溃窗口。
|
||||
* 这张表同时承担四件事:
|
||||
* 1. 防重复入队——主键是信箱 ID,同一条报文只会有一行;
|
||||
* 2. 防业务重复——IDENTITY_KEY 唯一,同一条业务报文只处理一次;
|
||||
* 3. 记录处理进度——状态、重试次数、下次重试时间和失败原因;
|
||||
* 4. 记录回填进度——处理完要把"已处理"标记写回共享信箱,写成功之前一直留着待办意图。
|
||||
*
|
||||
* 第 4 条和终态写在同一条 UPDATE 里,所以不会出现"业务处理完了,却没人记得去回填"。
|
||||
*/
|
||||
enum class ProcStatus { PENDING, FAILED, SUCCEEDED, SKIPPED, DEAD }
|
||||
enum class ProcStatus {
|
||||
/** 已入队,等待处理。 */
|
||||
PENDING,
|
||||
|
||||
/** 错误分类(design.md §2.3):MALFORMED/PROTOCOL 直接 DEAD 不重试;其余退避重试。 */
|
||||
enum class ErrorClass { MALFORMED, PROTOCOL, CODEC_ERROR, EXHAUSTED, INFRA, UNSUPPORTED }
|
||||
/** 处理失败,等退避时间到了再重试。 */
|
||||
FAILED,
|
||||
|
||||
/** 处理成功。 */
|
||||
SUCCEEDED,
|
||||
|
||||
/** 判定为业务重复,跳过不处理。 */
|
||||
SKIPPED,
|
||||
|
||||
/** 处理失败且不再重试,等人工处置。 */
|
||||
DEAD,
|
||||
}
|
||||
|
||||
/** 失败原因分类,决定失败后是重试还是直接进死信。 */
|
||||
enum class ErrorClass {
|
||||
/** 报文本身不合法,重试也没用,直接进死信。 */
|
||||
MALFORMED,
|
||||
|
||||
/** 整包被拒绝(运营日冲突、声明条数不符等),整包不落地,直接进死信。 */
|
||||
PROTOCOL,
|
||||
|
||||
/** 解码逻辑的问题;修好 codec 之后可以重放。 */
|
||||
CODEC_ERROR,
|
||||
|
||||
/** 重试次数用尽或队头滞留超时;人工复核后可以重放。 */
|
||||
EXHAUSTED,
|
||||
|
||||
/** 数据库、网络等基础设施抖动,重试通常就能过。 */
|
||||
INFRA,
|
||||
|
||||
/** 报文类型还没有对应处理器;属于能力未实现,先退避重试等补齐。 */
|
||||
UNSUPPORTED,
|
||||
}
|
||||
|
||||
data class ProcState(
|
||||
/** 信箱 CMINMSGS_ID,也是本表主键。 */
|
||||
val msgId: Long,
|
||||
val state: ProcStatus,
|
||||
val identityKey: String? = null, // SNDR|TYPE|STYP|SEQN(design.md §2.2);decode 后首次绑定,FAILED 重试不重绑
|
||||
/** 业务身份 SNDR|TYPE|STYP|SEQN;解码成功后绑定一次,重试不会重绑。 */
|
||||
val identityKey: String? = null,
|
||||
/** 处理失败次数,用来算退避档位和判断是否已到上限。 */
|
||||
val attempts: Int = 0,
|
||||
/** FAILED 状态下,下次可以重试的时刻。 */
|
||||
val nextAttemptAt: Instant? = null,
|
||||
val errorClass: ErrorClass? = null,
|
||||
/** 最近一次失败的原因(截断后落库,供排查)。 */
|
||||
val lastError: String? = null,
|
||||
/** 信箱 CMINMSGS_DATE_RECEIVED:§5.2 超期补写的 R 判据与 OPS-2「最老未处理信龄」锚点。 */
|
||||
/** 信箱里的接收时间:用来判断"超期仍未回填",也是最老未处理信龄的计算依据。 */
|
||||
val receivedAt: Instant? = null,
|
||||
/** 非空 = 已确认信箱行持有处理标记(回填完成)。 */
|
||||
/** 非空表示已确认信箱行带上了处理标记。 */
|
||||
val backfillAt: Instant? = null,
|
||||
/** 非空 = 待回填;终态事务内登记为 now,失败按退避推后。 */
|
||||
/** 非空表示还欠一次回填:写终态时置为当前时间,失败后退避推后。 */
|
||||
val backfillNextAt: Instant? = null,
|
||||
val backfillAttempts: Int = 0,
|
||||
val backfillError: String? = null,
|
||||
|
||||
Reference in New Issue
Block a user