docs: 统一生命周期与处理职责口径

This commit is contained in:
windyboy
2026-09-10 19:48:49 +08:00
parent 9fdb5ba6a5
commit dd839e6abb
5 changed files with 20 additions and 20 deletions
+1 -1
View File
@@ -52,7 +52,7 @@ CIIMS / AODB 等上游
|---|---| |---|---|
| `ingress` | 轮询信箱、持久化入队、补偿重扫及兼容 HTTP 写入;不解析业务报文。 | | `ingress` | 轮询信箱、持久化入队、补偿重扫及兼容 HTTP 写入;不解析业务报文。 |
| `codec` | XML 解码,区分非法报文与可修复的解码失败。 | | `codec` | XML 解码,区分非法报文与可修复的解码失败。 |
| `processing` | FIFO 调度、业务身份绑定与去重、处理器决策与落库(SCHD/FLOP/FDEL/ADFT):处理器在锁事务内完成状态写入、事件与回填待办登记,不直接触碰 Kafka。 | | `processing` | FIFO 调度、业务身份绑定与去重、领域决策与落库(SCHD/FLOP/FDEL/ADFT):纯领域逻辑只返回决策;Processor 作为事务协调器,在锁事务内完成状态写入、事件与回填意图登记,不直接触碰 Kafka。 |
| `delivery` | 消费待发事件,负责按目标保序、`schd` 聚合、投递和失败重试。 | | `delivery` | 消费待发事件,负责按目标保序、`schd` 聚合、投递和失败重试。 |
| `jobs` | 回填补偿扫描、航班历史清理与留痕保留期清理;独立 job 线程执行(调度见 design.md §6.1,红线见 flight-state.md §6),不参与 FIFO。 | | `jobs` | 回填补偿扫描、航班历史清理与留痕保留期清理;独立 job 线程执行(调度见 design.md §6.1,红线见 flight-state.md §6),不参与 FIFO。 |
| `domain` / `config` | 领域状态、事件和决策模型,以及运行参数。 | | `domain` / `config` | 领域状态、事件和决策模型,以及运行参数。 |
+5 -5
View File
@@ -17,7 +17,7 @@
| 记录 | 用途 | 关键约束 | | 记录 | 用途 | 关键约束 |
|---|---|---| |---|---|---|
| `PROC_STATE` | 入站消息的处理状态、身份、重试次数、错误原因与回填事实 | `MSG_ID = CMINMSGS_ID` 主键防止重复入队;`IDENTITY_KEY` 唯一约束防止业务重复;按最小未完成消息 ID 取队头;`RECEIVED_AT``BACKFILL_*` 承载 §5.2 超期判据与回填重试。 | | `PROC_STATE` | 入站消息的处理状态、身份、重试次数、错误原因与回填事实 | `MSG_ID = CMINMSGS_ID` 主键防止重复入队;`IDENTITY_KEY` 唯一约束防止业务重复;按最小未完成消息 ID 取队头;`RECEIVED_AT``BACKFILL_*` 承载 [message-lifecycle.md](message-lifecycle.md) §5.2 超期判据与回填重试。 |
| `MSG_EVENT` | 等待投递的事件(outbox) | `EVENT_ID` 决定投递顺序;`TARGET` 区分 `KAFKA:msg` / `KAFKA:schd``PARTITION_KEY` 恒为 `FLID``EVENT_TYPE` 区分 UPSERT 与 TOMBSTONE。 | | `MSG_EVENT` | 等待投递的事件(outbox) | `EVENT_ID` 决定投递顺序;`TARGET` 区分 `KAFKA:msg` / `KAFKA:schd``PARTITION_KEY` 恒为 `FLID``EVENT_TYPE` 区分 UPSERT 与 TOMBSTONE。 |
| `REQ_TRACK` | 上游请求及应答关联 | 保存请求类型、覆盖运营日、发送方、出站信箱 ID 与发送/完成时间;同类只允许一个开放请求。登记、超时与应答匹配尚未实现(§10)。 | | `REQ_TRACK` | 上游请求及应答关联 | 保存请求类型、覆盖运营日、发送方、出站信箱 ID 与发送/完成时间;同类只允许一个开放请求。登记、超时与应答匹配尚未实现(§10)。 |
| `REF_MASTER` | 静态参考数据(目标表) | `(RTYPE, RKEY)` 唯一;尚未建表,客户端与刷新流程见 user-stories.md US-13/US-14US-14 两类映射的存储落点未定)。 | | `REF_MASTER` | 静态参考数据(目标表) | `(RTYPE, RKEY)` 唯一;尚未建表,客户端与刷新流程见 user-stories.md US-13/US-14US-14 两类映射的存储落点未定)。 |
@@ -39,7 +39,7 @@ SNDR | TYPE | STYP | SEQN
接收时只按信箱 ID 去重;解码后才首次绑定业务身份。重试保留原有绑定,不能把自己判为重复消息。身份被另一条记录占用时,当前消息转为 `SKIPPED`,记录 `duplicate-of:<id>`。是否加入日期边界取决于上游序号重置规则,默认关闭;上线后不能随意更换身份算法。 接收时只按信箱 ID 去重;解码后才首次绑定业务身份。重试保留原有绑定,不能把自己判为重复消息。身份被另一条记录占用时,当前消息转为 `SKIPPED`,记录 `duplicate-of:<id>`。是否加入日期边界取决于上游序号重置规则,默认关闭;上线后不能随意更换身份算法。
分派与落库由 `MessageProcessor` 统一执行:按 `MsgKind` 把已绑定身份的队头消息交给对应处理器(DNLD/RESP → `ScheduleProcessor`ADFT → `AdftProcessor`FLOP → `FlopProcessor`FDEL → `FdelProcessor`,其余 → `FAILED(UNSUPPORTED)`)。处理器`PIPELINE_LOCK` 事务内读取当前完整态、计算下一态并落库登记事件与回填待办,不直接触碰 Kafka;提交与终态迁移仍由主泵边界负责(见 flight-state.md §4)。 分派与落库由 `MessageProcessor` 统一协调:按 `MsgKind` 把已绑定身份的队头消息交给对应事务协调器(DNLD/RESP → `ScheduleProcessor`ADFT → `AdftProcessor`FLOP → `FlopProcessor`FDEL → `FdelProcessor`,其余 → `FAILED(UNSUPPORTED)`)。这些 Processor `PIPELINE_LOCK` 事务内读取当前完整态,调用纯领域决策逻辑得到下一完整态与待发事件,再统一落库登记回填意图;它们不直接触碰 Kafka。处理终态与业务变更在同一事务边界提交(见 flight-state.md §4)。
### 2.3 状态与错误分类 ### 2.3 状态与错误分类
@@ -83,7 +83,7 @@ SNDR | TYPE | STYP | SEQN
2. 队头 `FAILED` 且未到 `next_attempt_at`:未超限则等到可重试时刻;已达重试上限或超过队头滞留时限(`head-deadline`,默认 10 分钟)则转 `DEAD(EXHAUSTED)` 2. 队头 `FAILED` 且未到 `next_attempt_at`:未超限则等到可重试时刻;已达重试上限或超过队头滞留时限(`head-deadline`,默认 10 分钟)则转 `DEAD(EXHAUSTED)`
3. 队头可执行:调用 `MessageProcessor.processOne`,失败迁移在该边界内完成。 3. 队头可执行:调用 `MessageProcessor.processOne`,失败迁移在该边界内完成。
维护作业由独立 job 线程调度(§6.1),不占用消息循环;作业有界且不使到期消息无限饥饿。滞留判据当前仍使用 `updatedAt` 与直取系统时间,未基于稳定起始时刻(§10)。 维护作业由独立 job 线程调度(§6.1),不占用消息循环;作业有界且不使到期消息无限饥饿。调度取时已经可注入 `Clock`,但滞留起点当前仍使用会随重试刷新的 `updatedAt`,尚未改为稳定起始时刻(§10)。
### 3.3 单条处理 ### 3.3 单条处理
@@ -141,7 +141,7 @@ REGISTERED → SENT → WAITING → DONE
`Dispatcher``TARGET` 读取最小未发送 `EVENT_ID`(当前逐条投递只处理 `KAFKA:msg`)。队头退避未到期时,该目标停止推进;发送确认后才标记 `SENT`,失败记录次数并按退避推后,达到上限转 `DEAD`(记录保留作 DLQ)。所有外部调用需要有界超时,避免阻塞整个投递线程。 `Dispatcher``TARGET` 读取最小未发送 `EVENT_ID`(当前逐条投递只处理 `KAFKA:msg`)。队头退避未到期时,该目标停止推进;发送确认后才标记 `SENT`,失败记录次数并按退避推后,达到上限转 `DEAD`(记录保留作 DLQ)。所有外部调用需要有界超时,避免阻塞整个投递线程。
投递是至少一次:下游已接收但本地未标记成功时可能重发。Kafka 生产约束沿用架构决策 D3architecture.md §7),但生产者幂等不替代应用层事件去重;跨重启的事件身份和下游去重契约仍需落实。共享出站信箱也必须单独解决重复写入,不能假设 Kafka 的保证适用于 MySQL。真实 Kafka 适配器尚未实现(`DeliveryPort` 仅有 stub),投递闭环须先交付适配与配置强制校验。 投递是至少一次:Kafka Broker 或其他投递目标已接受、但本地未标记成功时可能重发;目标端接受不等于业务消费者已消费。Kafka 生产约束沿用架构决策 D3architecture.md §7),但生产者幂等不替代应用层事件去重;跨重启的事件身份和消费方去重契约仍需落实。共享出站信箱也必须单独解决重复写入,不能假设 Kafka 的保证适用于 MySQL。真实 Kafka 适配器尚未实现(`DeliveryPort` 仅有 stub),投递闭环须先交付适配与配置强制校验。
### 5.2 `schd` 聚合 ### 5.2 `schd` 聚合
@@ -228,7 +228,7 @@ REGISTERED → SENT → WAITING → DONE
以下缺口直接影响上述设计是否成立,不能以类或接口已存在作为完成依据: 以下缺口直接影响上述设计是否成立,不能以类或接口已存在作为完成依据:
- **事务与外部副作用**:状态、事件、处理终态与回填意图同 PG 事务提交;回填意图落在 `PROC_STATE``BACKFILL_AT/NEXT_AT/ATTEMPTS/ERROR`),`BACKFILL_TODO` 已随 V2 迁移下线,[message-lifecycle.md](message-lifecycle.md) §4 的两个崩溃窗口(提交后回填前崩溃、待办二次落账失败)不再存在。回填本身仍是跨库单写,失败按退避重试并由超期期限 R 兜底;R 的取值待 Q6 确认。 - **事务与外部副作用**:状态、事件、处理终态与回填意图同 PG 事务提交;回填意图落在 `PROC_STATE``BACKFILL_AT/NEXT_AT/ATTEMPTS/ERROR`),`BACKFILL_TODO` 已随 V2 迁移下线,[message-lifecycle.md](message-lifecycle.md) §4 的两个崩溃窗口(提交后回填前崩溃、待办二次落账失败)不再存在。回填本身仍是跨库单写,失败按退避重试并由超期期限 R 兜底;R 的取值待 Q6 确认。
- **收报与调度**:水位 W 落库并与入队同事务推进,遇空洞即停、空洞超过 `max-commit-delay` 判定为永久(Q2 未书面确认前该阈值是假定值);较小 ID 迟提交与空洞场景的顺序保证仍待与库方联合验证。滞留判据仍使用 `updatedAt` 与系统时钟(已改经可注入 `Clock`),未基于稳定起始时刻(Q6)。 - **收报与调度**:水位 W 落库并与入队同事务推进,遇空洞即停、空洞超过 `max-commit-delay` 判定为永久(Q2 未书面确认前该阈值是假定值);较小 ID 迟提交与空洞场景的顺序保证仍待与库方联合验证。滞留判断已使用可注入 `Clock` 取时,但起点仍是会随重试刷新的 `updatedAt`,尚未改为稳定起始时刻(Q6)。
- **快照与业务能力**DNLD/RESP/ADFT 与 FLOP/FDEL 处理器、整包校验与跨运营日整包拒绝均已接入;但 RESP 应答守卫与出站请求未实现,忽略规则(US-04)未实现,29 类 FLOP 与参考应答的逐类矩阵未补全,ADFT 缺失字段与 `FLID` 重用语义待上游确认。 - **快照与业务能力**DNLD/RESP/ADFT 与 FLOP/FDEL 处理器、整包校验与跨运营日整包拒绝均已接入;但 RESP 应答守卫与出站请求未实现,忽略规则(US-04)未实现,29 类 FLOP 与参考应答的逐类矩阵未补全,ADFT 缺失字段与 `FLID` 重用语义待上游确认。
- **航班读写**:唯一写入口与权威读已落地;ROUT/ERUT 联合主键、空值/未知属性保真、事件在事务内只算一次、逐航班多次查询仍待修正(见 flight-state.md §6)。`/all/flights` 尚未实现。 - **航班读写**:唯一写入口与权威读已落地;ROUT/ERUT 联合主键、空值/未知属性保真、事件在事务内只算一次、逐航班多次查询仍待修正(见 flight-state.md §6)。`/all/flights` 尚未实现。
- **请求、参考数据与归档**`REQ_TRACK` 表与仓储已建,但无运行时协调与 `COUTMSGS` 出站适配;`REF_MASTER` 未建表;`PROC_STATE_HST` 未建表。航班历史清理脚手架已实现,历史存储未接通时删 0 条。 - **请求、参考数据与归档**`REQ_TRACK` 表与仓储已建,但无运行时协调与 `COUTMSGS` 出站适配;`REF_MASTER` 未建表;`PROC_STATE_HST` 未建表。航班历史清理脚手架已实现,历史存储未接通时删 0 条。
+1 -1
View File
@@ -42,7 +42,7 @@
## 3. 合并与写入语义 ## 3. 合并与写入语义
处理器保持纯粹:它根据当前完整态和已解码报文得到下一完整态与待发事件,持久化由统一事务入口执行 领域决策逻辑(如 `FlightStateEngine` 及各类 Handler 规则)保持纯粹:它根据当前完整态和已解码报文,返回下一完整态与待发事件,不执行数据库或 Kafka I/O。`ScheduleProcessor` / `FlopProcessor` / `FdelProcessor` / `AdftProcessor` 是事务协调器,负责在统一事务边界内调用决策逻辑并持久化结果
### 3.1 SCHD 日计划 ### 3.1 SCHD 日计划
+9 -9
View File
@@ -25,9 +25,9 @@
| 入队:本系统开始处理 | 自有 PG 建立 `PROC_STATE` 记录 | `InboxPoller` | | 入队:本系统开始处理 | 自有 PG 建立 `PROC_STATE` 记录 | `InboxPoller` |
| 处理完成:业务处理完成 | `PROC_STATE` 到达终态(SUCCEEDED / SKIPPED / DEAD | 主泵 | | 处理完成:业务处理完成 | `PROC_STATE` 到达终态(SUCCEEDED / SKIPPED / DEAD | 主泵 |
| 已回填:信箱写入处理标记 | 信箱行持有处理标记 | 回填与补偿通道 | | 已回填:信箱写入处理标记 | 信箱行持有处理标记 | 回填与补偿通道 |
| 下游确认:下游已接 | `MSG_EVENT``SENT` | `delivery`Dispatcher / flushSchd | | 投递确认:投递目标已接 | 目标端返回成功且 `MSG_EVENT``SENT` | `delivery`Dispatcher / flushSchd |
分环节的原因是存储边界:信箱与自有 PG 之间的写入不共享事务。前三个环节以自有 PG 为准;"已回填""下游确认"两个环节各自独立重试,都可能单独失败 分环节的原因是存储边界:信箱与自有 PG 之间的写入不共享事务。“落信”以共享 MySQL 为准,“入队”和“处理完成”以自有 PG 为准;已回填”与“投递确认”各以外部操作成功和本地确认事实共同判定。后两个环节各自独立重试,都可能单独失败。“投递确认”只表示 Kafka Broker 或其他投递目标已接受,不表示业务消费者已消费
## 2. 状态总纲 ## 2. 状态总纲
@@ -54,10 +54,10 @@ MSG_EVENT PENDING ──→ SENT
| 解码与身份 | 信箱原文 | `DecodedMessage``IDENTITY_KEY` | 身份唯一约束 | 报文非法→`DEAD`;处理能力不足→`FAILED` 退避 | | 解码与身份 | 信箱原文 | `DecodedMessage``IDENTITY_KEY` | 身份唯一约束 | 报文非法→`DEAD`;处理能力不足→`FAILED` 退避 |
| 事务处理 | 当前完整状态 + 报文载荷 | 航班变更、终态、事件、回填待办 | 消息 ID + 业务身份 | 事务整体回滚重试 | | 事务处理 | 当前完整状态 + 报文载荷 | 航班变更、终态、事件、回填待办 | 消息 ID + 业务身份 | 事务整体回滚重试 |
| 提交后回填 | 终态消息 | 信箱处理标记 | 标记单调(§11) | 终态事务内登记回填意图;失败退避重试,超期强制补写 | | 提交后回填 | 终态消息 | 信箱处理标记 | 标记单调(§11) | 终态事务内登记回填意图;失败退避重试,超期强制补写 |
| 投递 | `MSG_EVENT` | 下游确认 | `EVENT_ID` | 退避至 `DEAD`;至少一次 | | 投递 | `MSG_EVENT` | 投递目标接受确认 | `EVENT_ID` | 退避至 `DEAD`;至少一次 |
| 补偿作业 | 到期或已达 `NOW R` 的终态记录 | 追平标记 | 消息 ID(仅空标生效) | 指数退避,独立线程执行;`R` 覆盖退避 | | 补偿作业 | 到期或已达 `NOW R` 的终态记录 | 追平标记 | 消息 ID(仅空标生效) | 指数退避,独立线程执行;`R` 覆盖退避 |
处理器只在持有 `PIPELINE_LOCK` 的事务内写入自有 PG 状态,不操作信箱与 Kafka全部外部副作用发生在事务提交之后。 领域决策逻辑不执行 I/O;Processor 作为事务协调器,只在持有 `PIPELINE_LOCK` 的事务内写入自有 PG 状态,不操作信箱与 Kafka全部外部副作用发生在事务提交之后。
## 4. 故障恢复 ## 4. 故障恢复
@@ -65,12 +65,12 @@ MSG_EVENT PENDING ──→ SENT
| 中断位置 | 重启后的判定 | 恢复动作 | | 中断位置 | 重启后的判定 | 恢复动作 |
|---|---|---| |---|---|---|
| 已落信、未入队 | 信箱无标记且 PG 无记录 | 重扫补建入队记录 | | 已落信、未入队 | 信箱行位于应扫描的 ID 范围且 PG 无记录(不以处理标记为判据) | 重扫补建入队记录 |
| 事务执行中 | PG 无该消息终态 | 事务整体回滚,按 `PENDING` 重新处理 | | 事务执行中 | PG 无该消息终态 | 事务整体回滚,按 `PENDING` 重新处理 |
| 事务已提交、标记未写 | 终态行仍持有回填意图(`BACKFILL_NEXT_AT` 非空) | 仅补写标记;业务处理结果保持不变 | | 事务已提交、标记未写 | 终态行仍持有回填意图(`BACKFILL_NEXT_AT` 非空) | 仅补写标记;业务处理结果保持不变 |
| 回填待办登记失败(与业务同事务) | 事务未提交 | 同"事务执行中",不构成独立窗口 | | 回填待办登记失败(与业务同事务) | 事务未提交 | 同"事务执行中",不构成独立窗口 |
| 标记写入中途 | 标记仍为空 | 重新写入;重复写入同一值无副作用 | | 标记写入中途 | 标记仍为空 | 重新写入;重复写入同一值无副作用 |
| 下游已接`SENT` 未置 | 事件仍 `PENDING` | 允许重发,下游按事件身份去重 | | 投递目标已接`SENT` 未置 | 事件仍 `PENDING` | 允许重发,消费方按事件身份去重 |
两个窗口已随"终态与回填意图同体同行"消除(口径与 design.md §10「事务与外部副作用」一致),不再是缺口: 两个窗口已随"终态与回填意图同体同行"消除(口径与 design.md §10「事务与外部副作用」一致),不再是缺口:
@@ -98,11 +98,11 @@ MSG_EVENT PENDING ──→ SENT
### 5.2 超期标记补写 ### 5.2 超期标记补写
两类信箱行无法通过正常回填获得处理标记:报文残缺缺少元数据的死信,以及回填通道长期失败的行。处理规则为: 所有处理终态都只依赖消息 ID 执行回填;报文残缺缺少 META 不妨碍正常回填。本节规定回填通道长期失败时的超期兜底,避免终态信箱行无限期保持空标记。处理规则为:
**已达 `PROC_STATE` 终态、且接收时间超期(`DATE_RECEIVED < NOW R`)仍无标记的信箱行,由回填通道补写一个库方认可的"已处理"类标记。** **已达 `PROC_STATE` 终态、且接收时间超期(`DATE_RECEIVED < NOW R`)仍无标记的信箱行,由回填通道补写一个库方认可的"已处理"类标记。**
- 期限 `R` 必须不小于(人工重放期限 + 人工处置期限)之和;两项期限的取值口径分别见 Q6 与 Q9,确认前不得下调 `R`。提前补写会使仍可重放的消息先被库方清除、失去原件资格。 - 期限 `R` 必须不小于(人工重放期限 + 人工处置期限)之和;两项期限的取值口径统一见 Q6,确认前不得下调 `R`。提前补写会使仍可重放的消息先被库方清除、失去原件资格。
- 中间态(`PENDING` / `FAILED`)不适用本规则:处理未完成时不打标,也不允许被清除。 - 中间态(`PENDING` / `FAILED`)不适用本规则:处理未完成时不打标,也不允许被清除。
- 补写值仅限于库方认可的 legacy 值集(Q7);死信、业务重复等内部原因记录在 `PROC_STATE` 与审计日志,不在信箱新增枚举。 - 补写值仅限于库方认可的 legacy 值集(Q7);死信、业务重复等内部原因记录在 `PROC_STATE` 与审计日志,不在信箱新增枚举。
- 补写只针对空标记;已有值不回撤、不覆盖,重复执行无副作用。 - 补写只针对空标记;已有值不回撤、不覆盖,重复执行无副作用。
@@ -190,7 +190,7 @@ MSG_EVENT PENDING ──→ SENT
- 可重放的错误类别为 `CODEC_ERROR / UNSUPPORTED / INFRA / EXHAUSTED` 四类(以 design.md §6.1 为准);重放处理当前状态,不恢复历史顺序。 - 可重放的错误类别为 `CODEC_ERROR / UNSUPPORTED / INFRA / EXHAUSTED` 四类(以 design.md §6.1 为准);重放处理当前状态,不恢复历史顺序。
- 重放的前提是信箱原文仍可读取:`R_keep` 必须覆盖重放期限(§6),属于硬约束。 - 重放的前提是信箱原文仍可读取:`R_keep` 必须覆盖重放期限(§6),属于硬约束。
- 处理时无法读取原文,一律`MALFORMED → DEAD` 处理。若原文缺失源于库方违反保留契约提前清除,按契约违例走运维追责通道(契约条款见 Q7/Q9);该消息的死信处置本身不变。 - 确认信箱行或原文已缺失时,`MALFORMED → DEAD` 处理;共享库超时、连接失败等暂时性读取异常按 `INFRA` 退避重试,不得伪装成原文缺失。若原文缺失源于库方违反保留契约提前清除,按契约违例走运维追责通道(契约条款见 Q7/Q9);该消息的死信处置本身不变。
## 10. 开放问题索引 ## 10. 开放问题索引
+4 -4
View File
@@ -6,7 +6,7 @@
- 系统边界见 [architecture.md](architecture.md),模块流程见 [design.md](design.md)。本文不重复设计全文,也不以工单状态代替代码验收。消息生命周期与信箱清除见 [message-lifecycle.md](message-lifecycle.md),航班规则见 [flight-state.md](flight-state.md)。 - 系统边界见 [architecture.md](architecture.md),模块流程见 [design.md](design.md)。本文不重复设计全文,也不以工单状态代替代码验收。消息生命周期与信箱清除见 [message-lifecycle.md](message-lifecycle.md),航班规则见 [flight-state.md](flight-state.md)。
- “当前基础”来自本轮代码核对,只表示有接口或部分实现,不表示故事完成。`KEEP` 是保留业务兼容,`FIX` 是明确修正旧缺陷,`DEFERRED` 不进入阶段 A。 - “当前基础”来自本轮代码核对,只表示有接口或部分实现,不表示故事完成。`KEEP` 是保留业务兼容,`FIX` 是明确修正旧缺陷,`DEFERRED` 不进入阶段 A。
- “信箱落信、PG 入队、业务处理完成、信箱回填、下游确认”是五个独立事实,接口、日志和测试必须分开表达。 - “信箱落信、PG 入队、业务处理完成、信箱回填、目标端投递确认”是五个独立事实,接口、日志和测试必须分开表达。投递确认不等于业务消费者已消费。
- 所有内部迁移只落自有 PG;共享 MySQL 不建表、不增列、不写历史表。本文用 `DATE_PROCESSED / STATUS` 表示逻辑字段,实际列名以库方契约为准。 - 所有内部迁移只落自有 PG;共享 MySQL 不建表、不增列、不写历史表。本文用 `DATE_PROCESSED / STATUS` 表示逻辑字段,实际列名以库方契约为准。
- 验收条目可按 `US-xx/条目号` 引用。故事较大时按下文子范围拆成小 PR,不把一个故事等同于一个提交。 - 验收条目可按 `US-xx/条目号` 引用。故事较大时按下文子范围拆成小 PR,不把一个故事等同于一个提交。
@@ -76,16 +76,16 @@
**验收标准** **验收标准**
1. 只取最小未完成 ID`PENDING / FAILED` 均占队头;退避未到期不得越过。作业仅在无队头或退避窗口执行,已到期消息优先,作业有界且不会造成无限饥饿。 1. 只取最小未完成 ID`PENDING / FAILED` 均占队头;退避未到期不得越过。维护作业由独立线程执行,不参与消息 FIFO;作业必须有界且不得因争用资源使已到期消息无限饥饿。
2. 安全解码 XML,至少覆盖 META、SCHD、FLOP、参考应答与忽略类路由;合法但能力未支持是 `UNSUPPORTED`,不能一律归为非法报文。保留原文以支持诊断和回放。 2. 安全解码 XML,至少覆盖 META、SCHD、FLOP、参考应答与忽略类路由;合法但能力未支持是 `UNSUPPORTED`,不能一律归为非法报文。保留原文以支持诊断和回放。
3. 解码后首次绑定 `SNDR|TYPE|STYP|SEQN`;冲突转 `SKIPPED` 并记录原 ID;自身重试保留绑定。生产 `include-day-boundary=false`,更改算法须另行评审上游序号规则。 3. 解码后首次绑定 `SNDR|TYPE|STYP|SEQN`;冲突转 `SKIPPED` 并记录原 ID;自身重试保留绑定。生产 `include-day-boundary=false`,更改算法须另行评审上游序号规则。
4. `MALFORMED` 直接 `DEAD``CODEC_ERROR / UNSUPPORTED / INFRA` 按次数和退避处理,耗尽转 `DEAD(EXHAUSTED)`。不能无限重试未实现类型,也不能立即当非法报文丢弃。 4. `MALFORMED` 直接 `DEAD``CODEC_ERROR / UNSUPPORTED / INFRA` 按次数和退避处理,耗尽转 `DEAD(EXHAUSTED)`。不能无限重试未实现类型,也不能立即当非法报文丢弃。
5. HOL deadline 必须基于稳定起始时刻(必要时在 `PROC_STATE` 增加入队时间列),不能用每次重试刷新的 `updatedAt` 代替;调度判断注入 `Clock`。默认 5 次重试、10 分钟滞留限制;积压与人工重放的 deadline 边界按 Q6 验证。 5. HOL deadline 必须基于稳定起始时刻(必要时在 `PROC_STATE` 增加入队时间列),不能用每次重试刷新的 `updatedAt` 代替;调度判断注入 `Clock`。默认 5 次重试、10 分钟滞留限制;积压与人工重放的 deadline 边界按 Q6 验证。
6. 主泵在同一 PG 事务提交航班主表/明细、事件与处理结果;终态回填意图通过 US-09 同事务保存。任一步失败整体回滚;提交后只重试外部回填,不重复生成业务事件。 6. 主泵在同一 PG 事务提交航班主表/明细、事件与处理结果;终态回填意图通过 US-09 同事务保存。任一步失败整体回滚;提交后只重试外部回填,不重复生成业务事件。
7. 处理器只读取当前完整态、计算下一态,并把状态写入、事件与终态提交收敛在同一事务边界内,不直接触碰 Kafka失败只在持有消息上下文的边界落账,中断向上传递,不作为普通失败吞掉。 7. 领域决策逻辑只读取当前完整态与已解码报文,返回下一完整态和待发事件,不执行 I/O;Processor 作为事务协调器,将状态写入、事件、处理终态与回填意图收敛在同一事务边界内,不直接触碰 Kafka失败只在持有消息上下文的边界落账,中断向上传递,不作为普通失败吞掉。
8. 权威存储不可用或未完成恢复时停止业务处理;不能把“整个状态丢失”误判为“单航班不存在”而批量成功结束增量报文。 8. 权威存储不可用或未完成恢复时停止业务处理;不能把“整个状态丢失”误判为“单航班不存在”而批量成功结束增量报文。
**当前基础与落点**`processing/Pump.kt`(含 `MessageProcessor`)、`DynamicProcessors.kt``Identity.kt``codec/JacksonXmlCodec.kt``infra/retry/`。严格 FIFO 主泵、SCHDDNLD/RESP/ADFT/FLOP/FDEL 处理器、PG 单事务(含回填待办预登记)、身份绑定与重试已实现。尚未完成:忽略规则分支(US-04)、基于稳定起始时刻的滞留判据与可注入时钟、以及逐类矩阵与 golden 样例(US-05)。 **当前基础与落点**`processing/Pump.kt`(含 `MessageProcessor`)、`DynamicProcessors.kt``Identity.kt``codec/JacksonXmlCodec.kt``infra/retry/`。严格 FIFO 主泵、SCHDDNLD/RESP/ADFT/FLOP/FDEL 处理器、PG 单事务(含回填待办预登记)、身份绑定与重试已实现,调度取时已经由可注入 `Clock` 提供。尚未完成:忽略规则分支(US-04)、基于稳定起始时刻的滞留判据以及逐类矩阵与 golden 样例(US-05)。
**前置**:US-01Q1 已定单库方向,Q6 决定 deadline 边界。数据库迁移只落自有库。 **前置**:US-01Q1 已定单库方向,Q6 决定 deadline 边界。数据库迁移只落自有库。