2026-09-06 22:30:03 +08:00
# msgexchange-v2 设计文档
2026-09-07 15:10:57 +08:00
## 1. 阅读说明
2026-09-06 22:30:03 +08:00
2026-09-07 15:10:57 +08:00
本文说明模块如何协作、状态如何流转,以及失败后如何恢复。系统范围、存储归属和部署约束见 [architecture.md ](architecture.md ),不在这里重复。
2026-09-07 10:27:44 +08:00
2026-09-09 21:50:05 +08:00
运营航班权威状态只落自有 PostgreSQL(`FLIGHT_SCHD` 及资源明细表),Redis 已彻底退出动态权威与全部写路径;ES 历史投影属暂缓范围,不参与当前设计。
2026-09-07 10:27:44 +08:00
2026-09-09 21:50:05 +08:00
本文描述处理机制与流程;尚未交付的能力在本文件中明确标注,并以 §10 差异为准。航班状态规则统一由
2026-09-10 08:16:31 +08:00
[运营航班状态设计 ](flight-state.md ) 维护。
2026-09-08 18:50:34 +08:00
2026-09-07 15:10:57 +08:00
## 2. 数据与领域模型
2026-09-07 10:27:44 +08:00
2026-09-07 15:10:57 +08:00
### 2.1 持久化记录
2026-09-07 10:27:44 +08:00
2026-09-07 15:10:57 +08:00
所有内部表都属于自有 PostgreSQL;共享 MySQL 只保留约定的信箱读写边界。
2026-09-06 22:30:03 +08:00
2026-09-07 15:10:57 +08:00
| 记录 | 用途 | 关键约束 |
2026-09-06 22:30:03 +08:00
|---|---|---|
2026-09-09 21:50:05 +08:00
| `PROC_STATE` | 入站消息的处理状态、身份、重试次数和错误原因 | `MSG_ID = CMINMSGS_ID` 主键防止重复入队;`IDENTITY_KEY` 唯一约束防止业务重复;按最小未完成消息 ID 取队头。 |
| `MSG_EVENT` | 等待投递的事件(outbox) | `EVENT_ID` 决定投递顺序;`TARGET` 区分 `KAFKA:msg` / `KAFKA:schd` ; `PARTITION_KEY` 恒为 `FLID` ; `EVENT_TYPE` 区分 UPSERT 与 TOMBSTONE。 |
| `REQ_TRACK` | 上游请求及应答关联 | 保存请求类型、覆盖运营日、发送方、出站信箱 ID 与发送/完成时间;同类只允许一个开放请求。登记、超时与应答匹配尚未实现(§10)。 |
2026-09-10 08:16:31 +08:00
| `REF_MASTER` | 静态参考数据(目标表) | `(RTYPE, RKEY)` 唯一;尚未建表,客户端与刷新流程见 user-stories.md US-13/US-14( US-14 两类映射的存储落点未定)。 |
2026-09-09 21:50:05 +08:00
| `FLIGHT_SCHD` | 航班标量及单值异常字段 | `FLID` 主键;`OPERATION_DAY` 一经确定不可变;版本与最近消息 ID 用于追踪。变长资源集合存于 9 张明细表,规则见 [flight-state.md ](flight-state.md ) §2,不在此重复。 |
| `BACKFILL_TODO` | 共享信箱回填重试 | 回填意图与业务终态同事务预登记,提交后回填成功即删除;待办再次落账失败的崩溃窗口仍在(§10)。 |
| `PROC_STATE_HST` | 终态处理记录的归档目标 | 尚未建表;不得改写为共享库历史表。 |
2026-09-06 22:30:03 +08:00
2026-09-10 08:55:43 +08:00
字段与索引定义以 `src/main/resources/db/migration/V1__flight_state_baseline.sql` 为准;Oracle 11g 的迁移形态见 `src/main/resources/db/migration/oracle11g/` (占位,未接入任何 Flyway 配置)。报文原文仍从共享信箱读取,因此必须协调原文保留期,不能在消息尚需处理或重放时提前清理;生命周期、回填与清除契约的唯一定义见 [message-lifecycle.md ](message-lifecycle.md )。
2026-09-07 07:56:54 +08:00
2026-09-07 15:10:57 +08:00
### 2.2 消息、身份与决策
2026-09-06 22:30:03 +08:00
2026-09-09 21:50:05 +08:00
`XmlCodec` (实装 `JacksonXmlCodec` )将 XML 解码为 `DecodedMessage` ,包含 `SNDR / TYPE / STYP / SEQN / DTTM` 元数据、`MsgKind` 与业务载荷。解码失败区分 `MALFORMED` (报文非法,不重试)与可随 codec 修复的编码错误。`MsgKind` 为一等分派键:`Schd(RESP/DNLD/ADFT)` 、`Flop` 、`Fdel` 、`Unsupported` 。
2026-09-06 22:30:03 +08:00
2026-09-07 15:10:57 +08:00
业务身份统一由 `Identity.of` 生成:
2026-09-06 22:30:03 +08:00
2026-09-07 15:10:57 +08:00
```text
SNDR | TYPE | STYP | SEQN
2026-09-06 22:30:03 +08:00
```
2026-09-07 14:15:07 +08:00
2026-09-07 15:10:57 +08:00
接收时只按信箱 ID 去重;解码后才首次绑定业务身份。重试保留原有绑定,不能把自己判为重复消息。身份被另一条记录占用时,当前消息转为 `SKIPPED` ,记录 `duplicate-of:<id>` 。是否加入日期边界取决于上游序号重置规则,默认关闭;上线后不能随意更换身份算法。
2026-09-06 22:30:03 +08:00
2026-09-09 21:50:05 +08:00
分派与落库由 `MessageProcessor` 统一执行:按 `MsgKind` 把已绑定身份的队头消息交给对应处理器(DNLD/RESP → `ScheduleProcessor` , ADFT → `AdftProcessor` , FLOP → `FlopProcessor` , FDEL → `FdelProcessor` ,其余 → `FAILED(UNSUPPORTED)` )。处理器在 `PIPELINE_LOCK` 事务内读取当前完整态、计算下一态并落库、登记事件与回填待办,不直接触碰 Kafka;提交与终态迁移仍由主泵边界负责(见 flight-state.md §4)。
2026-09-06 22:30:03 +08:00
2026-09-07 15:10:57 +08:00
### 2.3 状态与错误分类
2026-09-06 22:30:03 +08:00
2026-09-07 15:10:57 +08:00
```text
处理:PENDING / FAILED → SUCCEEDED(成功)
2026-09-09 21:50:05 +08:00
→ SKIPPED(业务重复;忽略/无匹配分支见 US-04/US-06,尚未实现)
→ FAILED(等待退避重试)
→ DEAD( MALFORMED / PROTOCOL / EXHAUSTED,均需人工处置)
2026-09-06 22:30:03 +08:00
2026-09-07 15:10:57 +08:00
投递:PENDING → SENT
→ PENDING(退避后重试)
2026-09-09 21:50:05 +08:00
→ DEAD(重试耗尽,保留记录作 DLQ)
2026-09-07 15:10:57 +08:00
```
2026-09-06 22:30:03 +08:00
2026-09-07 15:10:57 +08:00
`SUCCEEDED / SKIPPED / DEAD` 是处理终态,不再阻塞后续消息;`FAILED` 不是终态,仍占据队头。`DEAD` 表示需要处置,不等于业务成功。
2026-09-06 22:30:03 +08:00
2026-09-07 15:10:57 +08:00
| 错误类别 | 处理方式 |
|---|---|
2026-09-09 21:50:05 +08:00
| `MALFORMED` | 报文非法或原文缺失,直接 `DEAD` ,不在重放白名单内。 |
| `PROTOCOL` | 整包协议拒绝(运营日冲突、声明数量不符、缺载荷等),立即 `DEAD` ,整包不落地、不重试。 |
2026-09-07 15:10:57 +08:00
| `CODEC_ERROR` | 解码能力问题,退避重试;修复后允许重放。 |
2026-09-09 21:50:05 +08:00
| `UNSUPPORTED` | 处理器或快照能力未实现,按可恢复失败处理,不直接当作非法报文;仍受重试上限约束。 |
2026-09-07 15:10:57 +08:00
| `INFRA` | 基础设施或执行异常,退避重试。 |
| `EXHAUSTED` | 重试耗尽或滞留超时,转 `DEAD` ,人工复核后允许重放。 |
2026-09-06 22:30:03 +08:00
2026-09-07 15:10:57 +08:00
## 3. 收报与主泵
2026-09-06 22:30:03 +08:00
2026-09-07 15:10:57 +08:00
### 3.1 收报
2026-09-06 22:30:03 +08:00
2026-09-09 21:50:05 +08:00
`InboxPoller` 默认每秒按 ID 升序、有限批次(`claim-batch` ,默认 50)读取 `DATE_PROCESSED IS NULL` 的信箱记录,经 `InboxEnqueue` 在自有 PG 建立 `PENDING` ;重复扫描幂等,入队失败留待下一轮。收报层不解析业务载荷,也不回填已处理标记。
2026-09-06 22:30:03 +08:00
2026-09-10 09:00:53 +08:00
水位的定义(连续上界、遇空洞即停)、扫描谓词与补偿窗口唯一见 [message-lifecycle.md ](message-lifecycle.md ) §5.1;水位不是已处理标记,其有效性以 Q2 的 ID 单调承诺为前提。快路径水位与受控补扫仍是目标形态,当前按 `afterId=0` 每轮全量扫描(§10),迟提交与空洞场景的顺序保证在启用前必须验证。
2026-09-06 22:30:03 +08:00
2026-09-07 15:10:57 +08:00
兼容 HTTP 入口执行“写入共享信箱 → PG 入队”。两步不在同一事务中:信箱成功而 PG 失败时,原文不能丢失,由轮询补建;客户端失败重试可能再次写信箱,业务身份去重仍然必需。
2026-09-06 22:30:03 +08:00
2026-09-07 15:10:57 +08:00
### 3.2 主泵调度
2026-09-06 22:30:03 +08:00
2026-09-09 21:50:05 +08:00
每次 `Pump.tick` 只围绕最小未完成消息(`PENDING` 与 `FAILED` 都占队头):
2026-09-06 22:30:03 +08:00
2026-09-09 21:50:05 +08:00
1. 无队头:按轮询间隔休眠。
2. 队头 `FAILED` 且未到 `next_attempt_at` :未超限则等到可重试时刻;已达重试上限或超过队头滞留时限(`head-deadline` ,默认 10 分钟)则转 `DEAD(EXHAUSTED)` 。
3. 队头可执行:调用 `MessageProcessor.processOne` ,失败迁移在该边界内完成。
2026-09-06 22:30:03 +08:00
2026-09-09 21:50:05 +08:00
维护作业由独立 job 线程调度(§6.1),不占用消息循环;作业有界且不使到期消息无限饥饿。滞留判据当前仍使用 `updatedAt` 与直取系统时间,未基于稳定起始时刻(§10)。
2026-09-07 14:15:07 +08:00
2026-09-07 15:10:57 +08:00
### 3.3 单条处理
2026-09-07 14:15:07 +08:00
2026-09-07 15:10:57 +08:00
```text
2026-09-09 21:50:05 +08:00
读取原文 → 解码(MALFORMED → DEAD;编码错误 → FAILED 退避)
→ 首次绑定身份(冲突 → SKIPPED,记 duplicate-of)
→ 按 MsgKind 分派处理器
DNLD / RESP → ScheduleProcessor(快照事务)
ADFT / FLOP / FDEL → Adft / Flop / FdelProcessor(单航班事务)
Unsupported → FAILED(UNSUPPORTED)
PG 单事务:锁 + 航班变更 + 待发事件 + 终态 + 回填待办预登记
→ 提交后回填信箱;失败由补偿待办重试
2026-09-07 15:10:57 +08:00
```
2026-09-09 21:50:05 +08:00
- 原文缺失归为 `MALFORMED` ;读取异常不能伪装成“缺失”,应进入基础设施重试。
- 忽略规则(`LDM / REGN / RSTA / EROR` → `SKIPPED` )尚未实现(§10);不能因类型未覆盖就把合法忽略报文当非法报文处理。
- 航班变更、待发事件、处理终态与回填待办在同一 PG 事务原子提交;跨存储双写窗口已根除。
2026-09-10 09:00:53 +08:00
- 终态回填发生在提交后:成功、业务重复与协议拒绝包持有可用 META 并回填;缺 META 或解码失败的死信不在常规回填范围,按超期补写规则处理([message-lifecycle.md ](message-lifecycle.md ) §5.2; US-09/Q7)。`PENDING / FAILED` 禁止回填;影子环境禁写。
2026-09-07 15:10:57 +08:00
## 4. 日计划快照与请求匹配
### 4.1 快照发布
2026-09-09 21:50:05 +08:00
`SCHD-DNLD` 与 `SCHD-RESP` 共用 `ScheduleProcessor.applyScheduleRecords` :
2026-09-07 15:10:57 +08:00
2026-09-09 21:50:05 +08:00
1. **重放判定** : `PROC_STATE` 已存在成功终态 → 幂等成功,仅追加留痕,不重复写入。
2026-09-09 22:17:04 +08:00
2. **整包校验** :声明记录数、航班标识与运营日推导等校验失败 → 整包 `DEAD(PROTOCOL)` ,不写半包,既有状态保持不变。
2026-09-09 21:50:05 +08:00
3. **事务写入** :锁内按 `FLID` 点查归属日,发现同一航班跨运营日即整包回滚并 `DEAD(PROTOCOL)` ;通过后合并写主表与资源明细。报文未携带的航班不因本次日计划报文被删除。
4. **提交结果** :同一事务保存 `KAFKA:schd` / `KAFKA:msg` 事件、置消息 `SUCCEEDED` 并预登记回填待办;事务提交后执行信箱回填,留痕在事务外追加。
2026-09-07 15:10:57 +08:00
2026-09-09 20:22:10 +08:00
单事务保证未提交变更整体回滚。消息重放由 `PROC_STATE` 的消息 ID 与业务身份控制;版本号不能单独证明消息身份。
2026-09-07 15:10:57 +08:00
2026-09-09 21:50:05 +08:00
**应答守卫仍是缺口** : `RESP` 应匹配开放 `RQFD` 请求(无匹配、过期或报文早于发送时间则不更新快照);当前 RESP 与 DNLD 无差别进入快照写入(§4.2/§10),不能视为 RESP 匹配闭环。
2026-09-07 15:10:57 +08:00
### 4.2 上游请求与静态数据
2026-09-09 21:50:05 +08:00
`REQ_TRACK` 表与仓储已存在(状态 `PENDING / SENT / DONE / EXPIRED` ),但没有运行时协调器:出站 `COUTMSGS` 适配、请求编码、超时与应答匹配均未实现(`XmlCodec.encodeRqrd` 只是占位)。本节是目标机制,不是现状。
请求生命周期目标:
2026-09-07 15:10:57 +08:00
```text
REGISTERED → SENT → WAITING → DONE
└──→ EXPIRED
```
2026-09-09 21:50:05 +08:00
- 注册同类新请求前使旧开放请求过期;只有 `COUTMSGS` 写入确认后才标记 `SENT` 并关联出站记录;写信箱成功但本地未确认的情况需要补偿与去重,不能无条件重新发送。
- 应答优先按已确认的回显字段精确匹配;回显契约未确认时的降级匹配(同类开放请求且 `DTTM ≥ sentAt` )存在跨代误配风险,必须明确接受并审计,不能宣称精确关联。比较前统一时区和时间单位。
- 参考应答写入自有 `REF_MASTER` (尚未建表),日计划应答走快照流程;请求完成必须在相应数据处理成功之后,超时和迟到应答不能修改已关闭请求对应的状态。
2026-09-07 15:10:57 +08:00
2026-09-09 21:50:05 +08:00
请求与参考数据的交付范围见 user-stories.md US-08/US-13/US-14 与 §10。
2026-09-07 15:10:57 +08:00
## 5. 事件投递
### 5.1 普通事件
2026-09-09 21:50:05 +08:00
`Dispatcher` 按 `TARGET` 读取最小未发送 `EVENT_ID` (当前逐条投递只处理 `KAFKA:msg` )。队头退避未到期时,该目标停止推进;发送确认后才标记 `SENT` ,失败记录次数并按退避推后,达到上限转 `DEAD` (记录保留作 DLQ)。所有外部调用需要有界超时,避免阻塞整个投递线程。
2026-09-07 15:10:57 +08:00
2026-09-09 21:50:05 +08:00
投递是至少一次:下游已接收但本地未标记成功时可能重发。Kafka 生产约束沿用架构决策 D3( architecture.md §7),但生产者幂等不替代应用层事件去重;跨重启的事件身份和下游去重契约仍需落实。共享出站信箱也必须单独解决重复写入,不能假设 Kafka 的保证适用于 MySQL。真实 Kafka 适配器尚未实现(`DeliveryPort` 仅有 stub),投递闭环须先交付适配与配置强制校验。
2026-09-07 15:10:57 +08:00
### 5.2 `schd` 聚合
2026-09-09 21:50:05 +08:00
`KAFKA:schd` 不进入逐条投递循环,只由 `flushSchd` 发送:
2026-09-07 15:10:57 +08:00
2026-09-09 21:50:05 +08:00
1. 到期领取批次:`mergePendingSchd` 按 `FLID` 合并未发事件,每个 `FLID` 只保留最新 `STATE_VERSION` ,批次大小受 `flush-limit` 约束。
2. 逐条发送:UPSERT 发送该 `FLID` 的最新整态(key = `FLID` );TOMBSTONE 发送 null 值删除通知。
3. 成功后把本批被代表的事件(含被最新版本合并压掉的旧事件)一起标记完成,推进 `lastFlush` ;失败的单条增加次数并退避,达到上限转 `DEAD` 。
2026-09-07 15:10:57 +08:00
2026-09-09 21:50:05 +08:00
默认聚合周期 3 秒、批上限 500。它提供最新状态通知,不保留每次中间变化;`KAFKA:msg` 与 `KAFKA:schd` 之间不承诺顺序。
2026-09-07 15:10:57 +08:00
## 6. 失败恢复与维护作业
### 6.1 失败、重试与重放
2026-09-09 21:50:05 +08:00
`ProcFailure` 与 `FailureScheduler` 统一处理侧失败落账,投递侧(`Dispatcher` )按同一套次数与退避规则迁移事件。默认最多 5 次(attempts ≥ 5 判耗尽),退避档位 1、2、4、8、16 秒、单档封顶 60 秒;时间经可注入 `Clock` 判定。
2026-09-07 15:10:57 +08:00
2026-09-09 21:50:05 +08:00
失败必须在持有具体消息、事件或批次的位置记录,外层循环只做兜底日志和等待,不重复增加次数。线程中断应恢复中断标记并向上传递;不把 JVM `Error` 当普通业务失败捕获。
2026-09-07 15:10:57 +08:00
2026-09-09 21:50:05 +08:00
`ReplayService` 只允许 `CODEC_ERROR / UNSUPPORTED / INFRA / EXHAUSTED` 从 `FAILED / DEAD` 回到 `PENDING` ,重置次数与下次执行时间,保留身份与错误审计。它按错误类整批重放,尚无按记录预检、操作审计与管理入口(US-10)。旧消息进入终态后后续消息可能已执行,**重新入队不等于恢复历史顺序**;人工重放前必须评估状态覆盖和版本保护,不能直接批量重放到生产。
2026-09-07 15:10:57 +08:00
2026-09-10 09:00:53 +08:00
**维护作业** : `JobRunner` 用独立 daemon 线程每 30 秒触发 `BackfillSweepJob` (回填补偿扫描,指数退避 30 秒起步、封顶 15 分钟),每天机场时区 03:30 后触发一次 `HistorySweepJob` (§6.2)。作业不再经 `PUMP_JOB` 队列插队,不参与消息 FIFO,也不使到期消息饥饿。作业与回填通道的生命周期口径见 [message-lifecycle.md ](message-lifecycle.md ) §3/§4。
2026-09-07 15:10:57 +08:00
2026-09-09 21:50:05 +08:00
### 6.2 历史清理与归档
2026-09-07 15:10:57 +08:00
2026-09-09 21:50:05 +08:00
**航班历史清理** ( `HistorySweepJob` ,每天 03:30 触发):按 `HistoryProps` 的保留期与终态/静默判据选出候选(含 `DELETED` ),先写历史存储,成功后物理删除主行与明细;历史存储未接通或 `history-store-enabled=false` 时删除 0 条。未经 FDEL、由生命周期直接清除的航班,清除前补发一次删除事件。语义与红线见 flight-state.md §6,不在此重复。
**留痕清理** : `SCHD_SNAP_LOG` 保留 90 天,在历史清理窗口内按 `(SCOPE_END, RECV_AT)` 删除。
2026-09-10 09:00:53 +08:00
**处理终态归档** : `PROC_STATE_HST` 仍是目标表(user-stories.md US-11),尚未建表;不得归档 `PENDING / FAILED` ,也不能因移走身份记录而失去业务去重能力。ES 历史投影(阶段 B)不启用。自有记录归档与信箱原文保留的关系见 [message-lifecycle.md ](message-lifecycle.md ) §8/§9。
2026-09-09 21:50:05 +08:00
共享信箱保留策略由库所有方管理;历史写入与删除事件入队之间仍需恢复方案,顺序调用不构成原子提交。
2026-09-07 15:10:57 +08:00
## 7. 接口与运行配置
兼容入口为 `POST /cminmsgs/send` ,请求体为原始 XML,当前成功响应为 HTTP 200、`text/plain` 格式的信箱记录 ID。这只表示接收结果,不表示业务处理成功。请求媒体类型、字符集和失败响应仍需与现役逐项对拍;查询与其他兼容端点不能因列入需求就视为已提供。
运行配置以 `application.yml` 、`application-dev.yml` 和 `.env.example` 为准,设计上重点区分:
2026-09-09 21:50:05 +08:00
- `pipeline.autostart` 与 `msgx.stubs` :分别控制管道启动与内存适配器;生产禁止 stub,默认不自动启动。
- `pipeline.poll-interval / claim-batch / max-attempts / backoff / head-deadline` :控制轮询节奏、批次、重试上限、退避与队头滞留;这些参数不能改变 FIFO。
2026-09-07 15:10:57 +08:00
- `schd.flush-period / flush-limit` :控制状态通知的聚合延迟与批量大小。
- `identity.include-day-boundary` :影响去重语义,不能作为普通调优项切换。
2026-09-09 21:50:05 +08:00
- `mailbox.shared-mysql.enabled` 与 `history.history-store-enabled` :分别门控真实信箱与历史存储接线,默认关闭。
2026-09-07 15:10:57 +08:00
日志关联消息 ID、事件 ID 和批次;失败记录错误分类、次数、下次执行时间。健康检查反映依赖实际可用性;队头滞留、积压、死信和补偿失败需要指标及告警。日志出口故障不得阻塞业务线程。
## 8. 验证要求
单元测试使用内存仓储和可推进的 `Clock` ,不依赖睡眠或在线中间件。以下不变量必须有回归测试,接口级单测不能替代主泵调度测试:
| 场景 | 必须验证的结果 |
|---|---|
| 重复扫描、入队中断、较小 ID 迟到 | 不重复入队、不丢记录、不让后续消息越序。 |
| 队头失败、退避及作业竞争 | 消息不越队;到期后恢复;作业不使消息无限饥饿。 |
| 同身份多条记录、失败后重试、归档后重复 | 只产生一次有效业务处理,不把自身重试判为重复。 |
2026-09-07 16:12:00 +08:00
| PG 事务失败、快照重复或迟到 | 整体回滚重试、不重复推进版本、不回退状态、不误删增量航班。 |
2026-09-09 21:50:05 +08:00
| 整包协议拒绝(运营日冲突、声明数不符) | 整包不落地、整体回滚,既有状态与版本不变,消息终态为 `DEAD(PROTOCOL)` 。 |
| PG 提交失败、信箱回填失败 | 事件与处理结果一起回滚;已提交结果只由回填待办补偿,不重放业务。 |
2026-09-07 15:10:57 +08:00
| 投递确认丢失、批次失败、次数耗尽 | 允许可识别的重发、保持目标顺序、整批退避并保留死信。 |
| 请求超时、无匹配 RESP、时间单位不一致 | 不误用迟到应答,不提前完成请求。 |
| stub 误配置、重复实例、停机中断 | 生产拒绝不安全启动,工作线程能正确退出。 |
2026-09-09 20:22:10 +08:00
真实适配器还需 PG 事务与补偿集成测试、日计划崩溃恢复测试、Kafka 故障投递验证;常规验证命令为 JDK 25 下执行 `./gradlew test` 。
2026-09-07 15:10:57 +08:00
## 9. 实现入口
生产代码根目录为 `src/main/kotlin/com/gzzn/omms/msgexchange/` :
| 关注点 | 主要入口 |
|---|---|
2026-09-09 21:50:05 +08:00
| 收报与兼容接口 | `ingress/InboxPoller.kt` 、`InboxEnqueue.kt` 、`InboxService.kt` 、`InboxController.kt` |
| 解码 | `codec/JacksonXmlCodec.kt` 、`SisWireMapper.kt` 、`SisMessageBody.kt` |
| 调度与处理 | `processing/Pump.kt` (含 `MessageProcessor` )、`DynamicProcessors.kt` ( FLOP/FDEL/ADFT)、`Identity.kt` |
| 日计划 | `processing/ScheduleProcessor.kt` ;请求协调尚无实现(`REQ_TRACK` 见 `infra/persistence/` ) |
| 投递与作业 | `delivery/Dispatcher.kt` 、`jobs/JobRunner.kt` 、`BackfillSweepJob.kt` 、`HistorySweepJob.kt` |
| 持久化与恢复 | `infra/persistence/` 、`infra/retry/` ( `ProcFailure` / `ReplayService` / `FailureScheduler` ) |
| 启停与配置 | `PipelineLifecycle.kt` 、`config/PipelineProps.kt` 、`config/HistoryProps.kt` |
2026-09-07 15:10:57 +08:00
## 10. 当前实现差异
以下缺口直接影响上述设计是否成立,不能以类或接口已存在作为完成依据:
2026-09-10 09:00:53 +08:00
- **事务与外部副作用**:状态、事件、终态与回填待办同 PG 事务已实现,回填失败落 `BACKFILL_TODO` 并由 `BackfillSweepJob` 到期重试。剩余缺口在“提交后回填前崩溃”与“待办落账再次失败”两个窗口,不能认定补偿最终必达;两个窗口的恢复判定见 [message-lifecycle.md ](message-lifecycle.md ) §4。
2026-09-09 21:50:05 +08:00
- **收报与调度**:轮询仍从 `afterId=0` 每轮全量扫描,持久水位与受控补扫未完成;较小 ID 迟提交与空洞场景的顺序保证未验证。滞留判据使用 `updatedAt` 与直取系统时间,未基于稳定起始时刻。
- **快照与业务能力**: DNLD/RESP/ADFT 与 FLOP/FDEL 处理器、整包校验与跨运营日整包拒绝均已接入;但 RESP 应答守卫与出站请求未实现,忽略规则(US-04)未实现,29 类 FLOP 与参考应答的逐类矩阵未补全,ADFT 缺失字段与 `FLID` 重用语义待上游确认。
- **航班读写**:唯一写入口与权威读已落地;ROUT/ERUT 联合主键、空值/未知属性保真、事件在事务内只算一次、逐航班多次查询仍待修正(见 flight-state.md §6)。`/all/flights` 尚未实现。
- **请求、参考数据与归档**: `REQ_TRACK` 表与仓储已建,但无运行时协调与 `COUTMSGS` 出站适配;`REF_MASTER` 未建表;`PROC_STATE_HST` 未建表。航班历史清理脚手架已实现,历史存储未接通时删 0 条。
- **生产与运维**:已有事务行锁,但没有整个实例的排他/FIFO 协调;真实 Kafka 与信箱出站适配未交付(仅 stub),配置允许环境变量覆盖 `acks` /幂等/in-flight;启动校验、影子隔离、告警与指标未闭环。对拍比较工具存在不等于现场对拍已完成。Oracle 11g 方言与迁移未接入验证。
2026-09-07 15:10:57 +08:00
2026-09-09 21:50:05 +08:00
业务契约与待确认事项见 [user-stories.md ](user-stories.md ),进度由 Plane 跟踪;本文件不维护工单流水账、测试数量或历史方案全文。