docs(acm2-75): 规范全面对齐新需求口径
specification.md 按新需求重写: - 扫描模型反转:水位/ID 区间 → 处理标记为谓词(C-30 取代 C-1/C-2/C-13;INV-2b 替代 INV-2/4/5) - Redis 回归为查询投影:处理完成门(INV-23)、投影治理与同源读取(INV-24),INV-11b 扩充非权威清单 - 日计划快照语义反转:缺席航班删除、未携带字段清除(INV-15b),增量报文语义另立(INV-14b) - 终态记录归档 → 到期删除(INV-25),G-PROC-HST/G-HST-RETENTION/G-REPLAY-CHANNEL/G-FLOP-DIRECTION 关闭并清扫全仓引用 - 重放移出交付范围:R_keep 公式收窄、CLM-3 重定义为重处理幂等、Q6 删除 - 新增 INV-23~28:Redis 完成门、投影治理、清理谓词、参考数据逐类保存/门控、历史先行红线 - C-25/C-26 定案(原子级联不回发 EROR;快照未携带字段清除),Q13/Q14 关闭,Q6/Q12 删除,新增 C-30/C-31 联动:implementation.md 收报/回填/快照/生命周期/FLOP 方向各章按新口径重写;architecture.md D1/D4 改删除语义;reference.md 退役 archive-after;requirements.md OPS 表改为注册表定义 语法;AGENTS.md 状态边界随新口径更新;check-docs.py OPS 注册表节名同步。 scripts/check-docs.sh 全部通过。
This commit is contained in:
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
### 架构与模块
|
### 架构与模块
|
||||||
- 模块边界:`ingress`, `codec`, `processing`, `delivery`, `jobs`, `domain`/`config`, `infra`。
|
- 模块边界:`ingress`, `codec`, `processing`, `delivery`, `jobs`, `domain`/`config`, `infra`。
|
||||||
- 状态边界:飞行状态仅存 PG,Redis 不属于运行时权威 (ACM2-28)。
|
- 状态边界:飞行状态权威只在自有 PG,Redis 仅作查询投影、不作权威或处理状态(docs/requirements.md「范围与非目标」)。
|
||||||
- 共享 MySQL 是外部邮箱边界:**严禁任何 Schema 变更或新建表**,只做契约内的读写与回填。
|
- 共享 MySQL 是外部邮箱边界:**严禁任何 Schema 变更或新建表**,只做契约内的读写与回填。
|
||||||
|
|
||||||
### 环境与构建陷阱
|
### 环境与构建陷阱
|
||||||
|
|||||||
+3
-3
@@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
| 事实 | 唯一归属 | 其他文档怎么写 |
|
| 事实 | 唯一归属 | 其他文档怎么写 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 水位 `W`、空洞判定与推进条件 | implementation.md「收报与水位」 | specification.md 写对库方的承诺 `C-1`–`C-3`;reference.md 写参数 |
|
| 收报扫描谓词与幂等登记 | implementation.md「收报」 | specification.md 写对库方的承诺 `C-30`;reference.md 写参数 |
|
||||||
| 保留期下界 `R_keep`、清除前置条件 | specification.md「契约」 | implementation.md 只写行为约束;执行步骤在上线前另立 |
|
| 保留期下界 `R_keep`、清除前置条件 | specification.md「契约」 | implementation.md 只写行为约束;执行步骤在上线前另立 |
|
||||||
| 处理标记值集与写权限 | specification.md `C-5` | implementation.md 只写行为约束「只写空标记、不回撤、不覆盖」(`INV-7`) |
|
| 处理标记值集与写权限 | specification.md `C-5` | implementation.md 只写行为约束「只写空标记、不回撤、不覆盖」(`INV-7`) |
|
||||||
| 回填四结果、放弃语义、`R` 的作用 | implementation.md「回填」 | specification.md 记结论与可声明性 |
|
| 回填四结果、放弃语义、`R` 的作用 | implementation.md「回填」 | specification.md 记结论与可声明性 |
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
| 航班动态逐类语义与空标签规则(FLOP) | implementation.md「动态运行事件」 | specification.md 记 `Q8` 与 `G-*`;requirements.md 写验收口径 |
|
| 航班动态逐类语义与空标签规则(FLOP) | implementation.md「动态运行事件」 | specification.md 记 `Q8` 与 `G-*`;requirements.md 写验收口径 |
|
||||||
| SIS 消息中的参考数据类别、结构与资源状态 | implementation.md「静态参考数据」 | requirements.md 写取数与刷新验收;admin-api 只从处理后的业务数据库读取 |
|
| SIS 消息中的参考数据类别、结构与资源状态 | implementation.md「静态参考数据」 | requirements.md 写取数与刷新验收;admin-api 只从处理后的业务数据库读取 |
|
||||||
| 对外术语(落信 / 入站 / 库方 / 处理标记) | specification.md「术语」 | — |
|
| 对外术语(落信 / 入站 / 库方 / 处理标记) | specification.md「术语」 | — |
|
||||||
| 管道内部术语(`W` / 队头 / 终态 / 回填意图) | implementation.md「术语与持久化记录」 | — |
|
| 管道内部术语(队头 / 终态 / 待标记 / 回填意图) | implementation.md「术语与持久化记录」 | — |
|
||||||
|
|
||||||
## 4. ID 定义语法与引用纪律
|
## 4. ID 定义语法与引用纪律
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
- 同一行登记多个 ID(如验证映射的 `INV-20 / CLM-3`)是引用行,不构成定义。
|
- 同一行登记多个 ID(如验证映射的 `INV-20 / CLM-3`)是引用行,不构成定义。
|
||||||
其他位置一律是引用。
|
其他位置一律是引用。
|
||||||
- 编号稳定:条款被取代时标 `[作废 by C-y]` 并保留原文;不静默改写,不重编号。
|
- 编号稳定:条款被取代时标 `[作废 by C-y]` 并保留原文;不静默改写,不重编号。
|
||||||
- **引用只用稳定 ID**,不用章节号:写 `INV-3`、`C-8`、`PARAM:msgx.pipeline.claim-batch`,或「见 implementation.md『收报与水位』」这类文件名 + 小节名指针。章节号随增删章节腐烂,指针失效后必然被改写为复述。
|
- **引用只用稳定 ID**,不用章节号:写 `INV-3`、`C-8`、`PARAM:msgx.pipeline.claim-batch`,或「见 implementation.md『收报』」这类文件名 + 小节名指针。章节号随增删章节腐烂,指针失效后必然被改写为复述。
|
||||||
- 指针之后**不再复述**被指内容。若两处需要同一段话,说明它放错了位置。
|
- 指针之后**不再复述**被指内容。若两处需要同一段话,说明它放错了位置。
|
||||||
- 外部 SIS 证据统一写 `SIS:<section>`(如 `SIS:3.16-note-4`),解析到 [legacy/SIS_AODB_RMS-V0.1.md](legacy/SIS_AODB_RMS-V0.1.md) 的章节;它不属于本项目规范 ID,不参与唯一定义检查。
|
- 外部 SIS 证据统一写 `SIS:<section>`(如 `SIS:3.16-note-4`),解析到 [legacy/SIS_AODB_RMS-V0.1.md](legacy/SIS_AODB_RMS-V0.1.md) 的章节;它不属于本项目规范 ID,不参与唯一定义检查。
|
||||||
- `G-NAME` 是活跃偏差 ID:定义只在 specification.md「当前已知偏差」注册表,其他位置只写标记;偏差闭合时在同一变更中删除定义与全仓引用,历史与关闭证据只留 Plane。
|
- `G-NAME` 是活跃偏差 ID:定义只在 specification.md「当前已知偏差」注册表,其他位置只写标记;偏差闭合时在同一变更中删除定义与全仓引用,历史与关闭证据只留 Plane。
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ CIIMS / AODB 等上游
|
|||||||
|
|
||||||
| 编号 | 决策及理由 | 证据 / 偏差 |
|
| 编号 | 决策及理由 | 证据 / 偏差 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| D1 | 航班清场只在历史写入成功后进行,未接通时删 0 条;未经 FDEL 的清场须先补发删除事件。ES 历史投影(阶段 B)暂缓。 | 红线见 [implementation.md](implementation.md)「生命周期」 |
|
| D1 | 航班清场只在历史写入成功后进行,未接通时删 0 条;未经 FDEL 的清场须先补发删除事件。历史写入是需求内交付(`US-14`),红线见 `INV-28`。 | 红线见 [implementation.md](implementation.md)「生命周期」 |
|
||||||
| D2 | 动态状态单写者,生产只允许一个活动实例;多实例必须先具备可靠的排他保护。 | 事务行锁见 [implementation.md](implementation.md)「事务边界」;实例级排他属 `PRE-5`,可声明性见 `CLM-6` |
|
| D2 | 动态状态单写者,生产只允许一个活动实例;多实例必须先具备可靠的排他保护。 | 事务行锁见 [implementation.md](implementation.md)「事务边界」;实例级排他属 `PRE-5`,可声明性见 `CLM-6` |
|
||||||
| D3 | Kafka 生产必须同时满足确认级别、幂等生产与单连接在途上限三项约束;不允许通过关闭幂等来满足生产接入。 | 取值见 [reference.md](reference.md) 参数表 |
|
| D3 | Kafka 生产必须同时满足确认级别、幂等生产与单连接在途上限三项约束;不允许通过关闭幂等来满足生产接入。 | 取值见 [reference.md](reference.md) 参数表 |
|
||||||
| D4 | 自有库终态记录只归档到 `PROC_STATE_HST`,不侵入共享库的表结构或保留策略。 | `G-PROC-HST` |
|
| D4 | 自有库终态处理记录到期直接删除,不归档;不侵入共享库的表结构或保留策略。 | 清理口径见 [implementation.md](implementation.md)「生命周期与清除」与 `INV-25` |
|
||||||
|
|||||||
+68
-96
@@ -25,16 +25,14 @@
|
|||||||
|
|
||||||
| 记录 | 用途 | 关键约束 |
|
| 记录 | 用途 | 关键约束 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `PROC_STATE` | 入站消息的处理状态、身份、尝试次数、错误原因与回填事实 | `MSG_ID = CMINMSGS_ID` 主键防重复入队;`IDENTITY_KEY` 唯一约束防业务重复;按最小未完成 `MSG_ID` 取队头;`BACKFILL_NEXT_AT` 非空 = 还欠一次回填,`BACKFILL_AT` 非空 = 标记已确认,`BACKFILL_ABANDONED_AT/REASON` 非空 = 已停止自动重试(**不等于**标记已确认);`RECEIVED_AT` 复制自信箱接收时间、**可能为 NULL**、仅用于对账与展示;`ENQUEUED_AT` 是本地入队时间、非空、是超期判据的唯一依据;归档后的去重影子行置 `STATE='ARCHIVED'`、只保留 `IDENTITY_KEY` 与 `MSG_ID`,不占队头、不触发回填、不参与积压聚合(`G-PROC-HST`)。 |
|
| `PROC_STATE` | 入站消息的处理状态、身份、尝试次数、错误原因与回填事实 | `MSG_ID = CMINMSGS_ID` 主键防重复入队;`IDENTITY_KEY` 唯一约束防业务重复;按最小未完成 `MSG_ID` 取队头;`BACKFILL_NEXT_AT` 非空 = 还欠一次回填,`BACKFILL_AT` 非空 = 标记已确认,`BACKFILL_ABANDONED_AT/REASON` 非空 = 已停止自动重试(**不等于**标记已确认);`RECEIVED_AT` 复制自信箱接收时间、**可能为 NULL**、仅用于对账与展示;`ENQUEUED_AT` 是本地入队时间、非空、是超期判据的唯一依据。 |
|
||||||
| `MSG_EVENT` | 等待投递的事件(outbox) | `EVENT_ID` 对 `KAFKA:msg` 是稳定事件身份并决定投递顺序;对 `KAFKA:schd` 是每次接受 upsert 时替换的写代次。`TARGET` 区分 `KAFKA:msg` / `KAFKA:schd`;`PARTITION_KEY` 当前取 `FLID`(`Q4` 定案前为假定,见 `C-29`);`EVENT_TYPE` 区分 UPSERT 与 TOMBSTONE。`KAFKA:schd` 按 `FLID` 单行 upsert,只保留最新 `STATE_VERSION`;`SENT_AT` 在投递确认的同一条 UPDATE 内写入,是保留期判定的唯一基准。 |
|
| `MSG_EVENT` | 等待投递的事件(outbox) | `EVENT_ID` 对 `KAFKA:msg` 是稳定事件身份并决定投递顺序;对 `KAFKA:schd` 是每次接受 upsert 时替换的写代次。`TARGET` 区分 `KAFKA:msg` / `KAFKA:schd`;`PARTITION_KEY` 当前取 `FLID`(`Q4` 定案前为假定,见 `C-29`);`EVENT_TYPE` 区分 UPSERT 与 TOMBSTONE。`KAFKA:schd` 按 `FLID` 单行 upsert,只保留最新 `STATE_VERSION`;`SENT_AT` 在投递确认的同一条 UPDATE 内写入,是保留期判定的唯一基准。 |
|
||||||
| `REQ_TRACK` | 上游请求及应答关联 | 状态 `PENDING / SENT / DONE / EXPIRED`;保存请求类型、覆盖运营日、发送方、出站信箱 ID 与发送/完成时间;**「同类只允许一个开放请求」的唯一键 = `(请求类型, 覆盖运营日, 发送方)`,且仅对开放状态生效**。 |
|
| `REQ_TRACK` | 上游请求及应答关联 | 状态 `PENDING / SENT / DONE / EXPIRED`;保存请求类型、覆盖运营日、发送方、出站信箱 ID 与发送/完成时间;**「同类只允许一个开放请求」的唯一键 = `(请求类型, 覆盖运营日, 发送方)`,且仅对开放状态生效**。 |
|
||||||
| `REF_MASTER` | SIS 消息提供的静态参考数据与资源状态(目标表) | `(RTYPE, RKEY)` 唯一;`RTYPE` 类别、合并语义与资源状态见「静态参考数据」;取数路径见 [requirements.md](requirements.md) `US-13`。 |
|
| `REF_MASTER` | SIS 消息提供的静态参考数据与资源状态(目标表) | `(RTYPE, RKEY)` 唯一;`RTYPE` 类别、合并语义与资源状态见「静态参考数据」;取数路径见 [requirements.md](requirements.md) `US-13`。 |
|
||||||
| `FLIGHT_SCHD` | 航班标量及单值异常字段 | `FLID` 主键;`OPERATION_DAY` 一经确定不可变;版本与最近消息 ID 用于追踪。变长集合存于资源明细表与 `FLIGHT_ROUTE_POINT`,规则见「航班域」。 |
|
| `FLIGHT_SCHD` | 航班标量及单值异常字段 | `FLID` 主键;`OPERATION_DAY` 一经确定不可变;版本与最近消息 ID 用于追踪。变长集合存于资源明细表与 `FLIGHT_ROUTE_POINT`,规则见「航班域」。 |
|
||||||
| `INBOX_CURSOR` | 消费水位 `W`、空洞计时 `holeSince`、播种事实 `SEEDED_AT` | 单行游标;`W` 只随新 ID 成功入队推进,遇空洞即停;`HOLE_SINCE` 持久化空洞观测时刻,进程重启不丢计时。`SEEDED_AT IS NULL` **不等于**从未消费(已有库新增列后同样为 NULL)。 |
|
|
||||||
| `SCHD_SNAP_LOG` | 日计划处理留痕 | 只追加、可重建,不参与状态决策;保留期见 [reference.md](reference.md)。 |
|
| `SCHD_SNAP_LOG` | 日计划处理留痕 | 只追加、可重建,不参与状态决策;保留期见 [reference.md](reference.md)。 |
|
||||||
| `PROC_STATE_HST` | 终态处理记录的归档目标 | 只归档到自有 PG,不落共享库历史表(`G-PROC-HST`、`G-HST-RETENTION`)。 |
|
字段与索引以 `src/main/resources/db/migration/` 的迁移链为准(Oracle 11g 目录为占位,未接入 Flyway)。报文原文仍从共享信箱读取,原文保留期必须满足 `C-7`;清除前提、保留期下界与处理标记值集见 `C-5`~`C-12`。
|
||||||
|
|
||||||
字段与索引以 `src/main/resources/db/migration/` 的迁移链为准(Oracle 11g 目录为占位,未接入 Flyway)。报文原文仍从共享信箱读取,原文保留期必须覆盖处理与重放窗口(`C-7`);清除前提、保留期下界与处理标记值集见 `C-5`~`C-12`。
|
|
||||||
|
|
||||||
## 2. 消息、身份与决策
|
## 2. 消息、身份与决策
|
||||||
|
|
||||||
@@ -44,15 +42,15 @@
|
|||||||
|
|
||||||
**身份绑定是独立的幂等单语句**(`WHERE IDENTITY_KEY IS NULL`),不参与业务事务。它的前提是「报文不可变」(`PRE-7`):同一身份的重发不会被比对内容,若上游改发正文会被判为重复并跳过(`Q15`)。
|
**身份绑定是独立的幂等单语句**(`WHERE IDENTITY_KEY IS NULL`),不参与业务事务。它的前提是「报文不可变」(`PRE-7`):同一身份的重发不会被比对内容,若上游改发正文会被判为重复并跳过(`Q15`)。
|
||||||
|
|
||||||
分派与落库由 `MessageProcessor` 协调:按 `MsgKind` 把已绑定身份的队头消息交给对应事务协调器(SCHD-DNLD/RESP → `ScheduleProcessor`,ADFT → `AdftProcessor`,FLOP → `FlopProcessor`,FDEL → `FdelProcessor`,`SIS:3.1`~`SIS:3.14` 的静态参考数据消息 → `ReferenceDataProcessor`,其余 → `FAILED(UNSUPPORTED)`)。这些处理器在 `PIPELINE_LOCK` 事务内读取当前完整态,调用纯领域决策逻辑得到下一完整态与待发事件,再统一落库并登记回填意图;它们不直接触碰 Kafka。领域决策逻辑不执行 I/O。
|
分派与落库由 `MessageProcessor` 协调:按 `MsgKind` 把已绑定身份的队头消息交给对应事务协调器(SCHD-DNLD/RESP → `ScheduleProcessor`,ADFT → `AdftProcessor`,FLOP → `FlopProcessor`,FDEL → `FdelProcessor`,`SIS:3.1`~`SIS:3.14` 的静态参考数据消息 → `ReferenceDataProcessor`,其余 → `SKIPPED(unsupported)`)。这些处理器在 `PIPELINE_LOCK` 事务内读取当前完整态,调用纯领域决策逻辑得到下一完整态与待发事件,再统一落库并登记回填意图;它们不直接触碰 Kafka。领域决策逻辑不执行 I/O。
|
||||||
|
|
||||||
忽略规则:解码后、分派前按大小写不敏感的 `TYPE-STYP` / `TYPE-*` 匹配忽略清单(基线 `LDM` / `EROR`,不混用 `ERROR`),命中转 `SKIPPED` 并记录 `ignored:<rule>`;忽略报文照常绑定身份,但不更新航班、不创建业务通知(`US-04`)。`REGN` / `RSTA` 是静态参考数据消息,必须分派给 `US-13`,不得忽略。
|
合法但本系统不支持的消息类型:跳过留档、按已处理写回标记(`US-03` AC2),不重试。`REGN` / `RSTA` 是静态参考数据消息,必须分派给 `US-13`,不得跳过。
|
||||||
|
|
||||||
## 3. 状态与错误分类
|
## 3. 状态与错误分类
|
||||||
|
|
||||||
```text
|
```text
|
||||||
处理:PENDING / FAILED → SUCCEEDED(成功)
|
处理:PENDING / FAILED → SUCCEEDED(成功)
|
||||||
→ SKIPPED(业务重复、忽略、无匹配)
|
→ SKIPPED(业务重复、忽略、不支持类型、无匹配)
|
||||||
→ FAILED(等待退避重试)
|
→ FAILED(等待退避重试)
|
||||||
→ DEAD(MALFORMED / PROTOCOL / EXHAUSTED,均需人工处置)
|
→ DEAD(MALFORMED / PROTOCOL / EXHAUSTED,均需人工处置)
|
||||||
|
|
||||||
@@ -61,47 +59,34 @@
|
|||||||
→ DEAD(重试耗尽,记录保留作 DLQ)
|
→ DEAD(重试耗尽,记录保留作 DLQ)
|
||||||
```
|
```
|
||||||
|
|
||||||
`SUCCEEDED / SKIPPED / DEAD` 是处理终态,不再阻塞后续消息;`FAILED` 不是终态,仍占据队头。`DEAD` 表示需要处置,不等于业务成功。`ARCHIVED` 不是处理态:它是终态行归档后留在主表的去重影子行,不占队头、不触发回填、不参与积压聚合(见「生命周期与清除」)。
|
`SUCCEEDED / SKIPPED / DEAD` 是处理终态,不再阻塞后续消息;`FAILED` 不是终态,仍占据队头。`DEAD` 表示需要处置,不等于业务成功。
|
||||||
|
|
||||||
重试次数用尽时统一转 `DEAD(EXHAUSTED)`:`ERROR_CLASS` 被覆写为 `EXHAUSTED`,原始错误类别不再保留(`LAST_ERROR` 保留原因文本)。重放白名单与错误分类表见 [reference.md](reference.md)「错误分类与重放白名单」。
|
重试次数用尽时统一转 `DEAD(EXHAUSTED)`:`ERROR_CLASS` 被覆写为 `EXHAUSTED`,原始错误类别不再保留(`LAST_ERROR` 保留原因文本)。重放白名单与错误分类表见 [reference.md](reference.md)「错误分类与重放白名单」。
|
||||||
|
|
||||||
## 4. 收报与水位
|
## 4. 收报
|
||||||
|
|
||||||
### 4.1 收报流程
|
### 4.1 收报流程
|
||||||
|
|
||||||
`InboxPoller` 按 ID 升序、有限批次读取水位之后的信箱记录(`ID > W`,**不以处理标记为谓词**),在自有 PG 建立 `PENDING` 并把水位推进到连续上界。每轮:
|
`InboxPoller` 按配置周期查信箱中「处理标记为空」的行,按编号升序、每批有上限,在自有 PG 登记 `PENDING`(`INV-2b`)。每轮:
|
||||||
|
|
||||||
1. 读取游标 `(W, holeSince)`。信箱不可读时记日志、等下一轮,**不动水位**——这是基础设施失败,不能当成「没有新消息」。
|
1. 信箱不可读时记日志、等下一轮——这是基础设施失败,不能当成「没有新消息」。
|
||||||
2. 取 `ID > W` 的升序前 `PARAM:msgx.pipeline.claim-batch` 行。
|
2. 取「处理标记为空」的行的升序前 `PARAM:msgx.pipeline.claim-batch` 条。
|
||||||
3. 从 `W+1` 起逐 1 数,求连续上界;遇到第一个缺号即停止计数。
|
3. 在同一个 PG 事务内对每一行 `insertIfAbsent(MSG_ID, RECEIVED_AT, ENQUEUED_AT)`;主键冲突表示已登记(重复扫描与兼容入口并发都安全),不计入、不报错。
|
||||||
4. 空洞判定(仅当本批存在「缺号之后的行」时才可能成立):
|
4. 提交。已打标的行不再出现在扫描结果里;终态但未回填的行会被重复读到,按已有记录幂等跳过。
|
||||||
- 缺号首次被观测到 → `holeSince = now`;
|
|
||||||
- `now − holeSince < PARAM:msgx.pipeline.max-commit-delay` → 水位停在缺号前,**本批缺号之后的行一律不入队**(否则晚提交的较小 ID 会排到它们后面,破坏 FIFO);
|
|
||||||
- `now − holeSince ≥ PARAM:msgx.pipeline.max-commit-delay` → 判定为永久空洞,水位放行到「缺号后第一行 − 1」并清空 `holeSince`。放行**只跳过空洞本身,不越过任何已存在的行**。
|
|
||||||
5. 在同一个 PG 事务内:对水位以内的每一行 `insertIfAbsent(MSG_ID, RECEIVED_AT, ENQUEUED_AT)` 并写回 `(W, holeSince)`;主键冲突表示已入队(重复扫描与兼容入口并发都安全),不计入、不报错。
|
|
||||||
6. 提交。本批因空洞或批次上限未入队的行留待下一轮——**每轮最多解决一个空洞**。
|
|
||||||
|
|
||||||
`holeSince` 落在 `INBOX_CURSOR.HOLE_SINCE`,进程重启不丢计时。旧空洞补齐后出现的新空洞从新观测时刻重新计时,不继承旧等待时间。
|
**代价(必须接受并观测)**:回填延迟期内同一行会被反复读到并幂等跳过,扫描量随「终态未回填」行数增长。运行期必须观测扫描量与积压(指标见 [reference.md](reference.md))。
|
||||||
|
|
||||||
**代价(必须接受并观测)**:水位遇空洞即停意味着空洞之后的所有消息最多要等一个老化窗口才能入队;自增回滚等会在 ID 序列留下永久空位,每出现一个永久空位就是一次等长的入队停摆,空位频繁时有效吞吐按比例下降。运行期必须观测永久空洞计数与水位滞后(指标见 [reference.md](reference.md))。
|
### 4.2 顺序依据
|
||||||
|
|
||||||
### 4.2 发现完整性依赖
|
编号即到达顺序的前提见 `PRE-2`/`PRE-3`(`C-30`/`C-3`):ID 按提交顺序分配、空间不复位不复用。较小编号迟提交的最坏结果是被发现得晚(下一轮扫描仍会读到),不会丢。
|
||||||
|
|
||||||
水位的有效性依赖 `PRE-2`、`PRE-3`(`C-1`/`C-2`/`C-3`)。承诺缺失时 `W` 只是快路径提示,不足以证明该区间收齐。ID 分配 → 事务可见时延上界必须由库方直接给出,**不可由 SIS 报文 `Expiry` 推导**。
|
### 4.3 兼容 HTTP 入口
|
||||||
|
|
||||||
日常扫描只有一条快路径:`ID > W ORDER BY ID ASC LIMIT claim-batch`。
|
`POST /cminmsgs/send` 把报文写入共享信箱(处理标记为空),效果与上游投递一致:由收报扫描发现、登记、处理。客户端失败重试可能再次写信箱,业务身份去重仍然必需。响应语义见 `C-28`。
|
||||||
|
|
||||||
### 4.3 切流播种
|
### 4.4 单实例
|
||||||
|
|
||||||
若信箱已有存量(典型情况是最老分区已被清除、`MIN(ID)` 远大于 1),从 `W=0` 启动会先把 `ID=1` 判成空洞、白等一个老化窗口。是否跳过存量属于**切流决策**,因此不做默认选择:只有显式配置 `PARAM:msgx.pipeline.cutover-watermark` 才播种,取值 `min`(读现存全部)/ `zero`(从 0 按空洞规则)/ `max`(跳过当前可见存量)/ 具体 ID。升级实例(已有水位或已有处理记录)拒绝重新播种;播种事实与水位同语句落库(`SEEDED_AT`)。
|
信箱读取不加锁,本设计只在单活动实例下成立(`PRE-5`)。多实例并发扫描会重复登记同一行,主键幂等兜底不会丢消息,但实例级排他仍是前提。
|
||||||
|
|
||||||
### 4.4 兼容 HTTP 入口
|
|
||||||
|
|
||||||
`POST /cminmsgs/send` 执行「写入共享信箱 → PG 入队」,两步不在同一事务:信箱成功而 PG 失败时原文仍在信箱中,由轮询补建;客户端失败重试可能再次写信箱,业务身份去重仍然必需。该入口直接写 `PROC_STATE`、不读不推水位,登记的行因此**超出水位**;主泵只领 `MSG_ID ≤ W`,所以在水位追平前不会被处理——顺序不受影响,代价是延迟到追平,且必须让收报轮询运行。响应语义见 `C-28`。
|
|
||||||
|
|
||||||
### 4.5 单实例与水位
|
|
||||||
|
|
||||||
信箱读取不加锁,水位是单行覆盖写,本设计只在单活动实例下成立(`PRE-5`)。多实例并发收报会让水位互相覆盖(覆盖回退只会造成重复扫描,不会丢消息,但空洞计时会失真),必须先有实例级排他。
|
|
||||||
|
|
||||||
## 5. 主泵调度与单条处理
|
## 5. 主泵调度与单条处理
|
||||||
|
|
||||||
@@ -110,14 +95,13 @@
|
|||||||
每次 `Pump.tick` 只围绕最小未完成消息:
|
每次 `Pump.tick` 只围绕最小未完成消息:
|
||||||
|
|
||||||
1. 无队头:按轮询间隔休眠。
|
1. 无队头:按轮询间隔休眠。
|
||||||
2. 队头超出水位(`msgId > W`):**不领取**,休眠到下一轮。这类行只可能来自兼容入口的直接登记;允许领取会让它越过尚未入队的较小 ID。会打印一条限流 WARN(仅在水位值变化时打一次)。
|
2. 队头为 `FAILED` 且尝试次数达上限:转 `DEAD(EXHAUSTED)`,终态与回填意图同一条 UPDATE 落库,**不做跨库写**。该分支只写 `PROC_STATE`,不取 `PIPELINE_LOCK`、不在处理器事务内,也不在 `MessageLifecycleGate` 内。
|
||||||
3. 队头为 `FAILED` 且尝试次数达上限:转 `DEAD(EXHAUSTED)`,终态与回填意图同一条 UPDATE 落库,**不做跨库写**。该分支只写 `PROC_STATE`,不取 `PIPELINE_LOCK`、不在处理器事务内,也不在 `MessageLifecycleGate` 内。
|
3. 队头为 `FAILED` 且未到 `next_attempt_at`:休眠到可重试时刻,不处理后续消息。
|
||||||
4. 队头为 `FAILED` 且未到 `next_attempt_at`:休眠到可重试时刻,不处理后续消息。
|
4. 其余(新消息或退避到期的重试):调用 `MessageProcessor.processOne`,失败迁移在该边界内完成。
|
||||||
5. 其余(新消息或退避到期的重试):调用 `MessageProcessor.processOne`,失败迁移在该边界内完成。
|
|
||||||
|
|
||||||
**终态判据只有尝试上限,没有按时间的毒丸**:处理卡死应由外部调用的有界超时兜底;用一个时间阈值把消息直接推入 `DEAD` 会绕过人工复核,并制造与人工重放并发的旁路写入者。队头年龄由 `msgx.pipeline.backlog.oldest_unprocessed_seconds` 观测,主泵不做这项判定。
|
**终态判据只有尝试上限,没有按时间的毒丸**:处理卡死应由外部调用的有界超时兜底;用一个时间阈值把消息直接推入 `DEAD` 会绕过人工复核,并制造与人工重放并发的旁路写入者。队头年龄由 `msgx.pipeline.backlog.oldest_unprocessed_seconds` 观测,主泵不做这项判定。
|
||||||
|
|
||||||
**所有取时统一经注入 `Clock`**(收报空洞老化、主泵调度、处理器落库时间、回填重试、作业切日),不使用系统时钟。
|
**所有取时统一经注入 `Clock`**(主泵调度、处理器落库时间、回填重试、作业切日),不使用系统时钟。
|
||||||
|
|
||||||
### 5.2 processOne
|
### 5.2 processOne
|
||||||
|
|
||||||
@@ -131,31 +115,29 @@ processOne(head):
|
|||||||
已被本消息占用 → 继续
|
已被本消息占用 → 继续
|
||||||
已被别的消息占用 → SKIPPED(duplicate-of:<id>),结束
|
已被别的消息占用 → SKIPPED(duplicate-of:<id>),结束
|
||||||
空闲 → 写入 IDENTITY_KEY(独立单语句,不参与业务事务)
|
空闲 → 写入 IDENTITY_KEY(独立单语句,不参与业务事务)
|
||||||
4. 忽略规则命中 → SKIPPED(ignored:<rule>)(非业务型终态)
|
4. 按 MsgKind 分派:
|
||||||
5. 按 MsgKind 分派:
|
|
||||||
SCHD-DNLD / SCHD-RESP → ScheduleProcessor(快照事务)
|
SCHD-DNLD / SCHD-RESP → ScheduleProcessor(快照事务)
|
||||||
SCHD-ADFT → AdftProcessor(单航班事务)
|
SCHD-ADFT → AdftProcessor(单航班事务)
|
||||||
FLOP / FDEL → Flop / FdelProcessor(单航班事务)
|
FLOP / FDEL → Flop / FdelProcessor(单航班事务)
|
||||||
Unsupported → FAILED(UNSUPPORTED) 退避
|
Unsupported → SKIPPED(unsupported)(跳过留档,按已处理写回标记)
|
||||||
载荷缺失 → DEAD(MALFORMED)
|
载荷缺失 → DEAD(MALFORMED)
|
||||||
整包协议拒绝 → DEAD(PROTOCOL),不落半包
|
整包协议拒绝 → DEAD(PROTOCOL),不落半包
|
||||||
6. 业务型成功:处理器在自己的事务内写航班变更 + 待发事件 + SUCCEEDED + 回填意图
|
5. 业务型成功:处理器在自己的事务内写航班变更 + 待发事件 + SUCCEEDED + 回填意图
|
||||||
7. 结束:主泵不做回填;回填意图已随终态落库,由扫描补写信箱标记
|
6. 结束:主泵不做回填;回填意图已随终态落库,由扫描补写信箱标记
|
||||||
```
|
```
|
||||||
|
|
||||||
- 原文缺失归为 `MALFORMED`;读取异常按基础设施失败进入重试,与「原文缺失」区分。
|
- 类型未覆盖不等于报文非法:不支持的消息类型跳过留档、按已处理写回标记,不按 `MALFORMED` 处理。
|
||||||
- 类型未覆盖不等于报文非法:忽略类报文在规则实现前不按 `MALFORMED` 处理。
|
|
||||||
- **主泵不回填**:终态与回填意图由同一条 UPDATE 落库,回填一律由扫描驱动,不占用 FIFO 关键路径。回填只需消息 ID,缺 META 或解码失败的死信同样可补写。影子环境禁写。
|
- **主泵不回填**:终态与回填意图由同一条 UPDATE 落库,回填一律由扫描驱动,不占用 FIFO 关键路径。回填只需消息 ID,缺 META 或解码失败的死信同样可补写。影子环境禁写。
|
||||||
|
|
||||||
### 5.3 事务边界
|
### 5.3 事务边界
|
||||||
|
|
||||||
| 动作 | 显式事务 | 持 `PIPELINE_LOCK` | 触及航班表 / 事件 | 原子性来源 |
|
| 动作 | 显式事务 | 持 `PIPELINE_LOCK` | 触及航班表 / 事件 | 原子性来源 |
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
| 收报入队(`insertIfAbsent` + `cursor.save`) | 是 | 否 | 否 | 同库事务 |
|
| 收报入队(`insertIfAbsent`) | 是 | 否 | 否 | 同库事务 |
|
||||||
| 身份首次绑定 | 否 | 否 | 否 | 单语句 + 唯一约束 |
|
| 身份首次绑定 | 否 | 否 | 否 | 单语句 + 唯一约束 |
|
||||||
| 业务型终态(处理器产出 `SUCCEEDED`) | 是 | 是 | 是 | 同库事务:航班变更 + 事件 + 终态 + 回填意图 |
|
| 业务型终态(处理器产出 `SUCCEEDED`) | 是 | 是 | 是 | 同库事务:航班变更 + 事件 + 终态 + 回填意图 |
|
||||||
| 非业务型终态(`MALFORMED` / `PROTOCOL` / `SKIPPED` / `EXHAUSTED`) | 否 | 否 | 否 | 单语句(终态与回填意图同一条 UPDATE) |
|
| 非业务型终态(`MALFORMED` / `PROTOCOL` / `SKIPPED` / `EXHAUSTED`) | 否 | 否 | 否 | 单语句(终态与回填意图同一条 UPDATE) |
|
||||||
| 航班历史清理的物理删除 | 是 | 是(`INV-18`) | 是 | 同库事务:复查判据 + 归档成功后删除 |
|
| 航班历史清理的物理删除 | 是 | 是(`INV-18`) | 是 | 同库事务:复查判据 + 历史写入成功后删除 |
|
||||||
| 回填(信箱标记 + `BACKFILL_AT`) | 否 | 否 | 否 | 跨库两次单写;幂等可重跑 |
|
| 回填(信箱标记 + `BACKFILL_AT`) | 否 | 否 | 否 | 跨库两次单写;幂等可重跑 |
|
||||||
| 人工重放(批量改回 `PENDING`) | 否 | 否 | 否 | 单语句批量;`MessageLifecycleGate` 与回填互斥 |
|
| 人工重放(批量改回 `PENDING`) | 否 | 否 | 否 | 单语句批量;`MessageLifecycleGate` 与回填互斥 |
|
||||||
|
|
||||||
@@ -168,7 +150,7 @@ processOne(head):
|
|||||||
- 顺序由 `MSG_ID` 决定,不由执行方式决定。入队与处理由不同线程驱动、可以并发,「先入队后处理」只是可选的运维规程,不是正确性前提;系统不提供「只入队」模式。
|
- 顺序由 `MSG_ID` 决定,不由执行方式决定。入队与处理由不同线程驱动、可以并发,「先入队后处理」只是可选的运维规程,不是正确性前提;系统不提供「只入队」模式。
|
||||||
- 不加速、不分流、不走旁路:不允许并行队头,也不允许实时消息跳过积压。
|
- 不加速、不分流、不走旁路:不允许并行队头,也不允许实时消息跳过积压。
|
||||||
- 尝试上限与退避对积压同样生效,不因积压而放宽。
|
- 尝试上限与退避对积压同样生效,不因积压而放宽。
|
||||||
- 经确认不再处理的行置 `SKIPPED` 并记录原因,到达终态后走回填通道;不存在「整段 DELETE」的快速通道(授权与留痕见 `C-27`/`Q12`)。
|
- 不再处理的行置 `SKIPPED` 并记录原因,到达终态后走回填通道;不存在「整段 DELETE」的快速通道。
|
||||||
- 消化期间的可观测项与完成时限口径见 [reference.md](reference.md) 与 `CLM-9`:**扫描周期不是完成时限**。
|
- 消化期间的可观测项与完成时限口径见 [reference.md](reference.md) 与 `CLM-9`:**扫描周期不是完成时限**。
|
||||||
|
|
||||||
## 6. 回填
|
## 6. 回填
|
||||||
@@ -216,9 +198,9 @@ LIMIT PARAM:msgx.pipeline.backfill-batch
|
|||||||
2. 到 `R` 仍失败则停止自动重试、告警,进入放弃清单,保留人工恢复(`reopen`);
|
2. 到 `R` 仍失败则停止自动重试、告警,进入放弃清单,保留人工恢复(`reopen`);
|
||||||
3. `C-8` 允许以「放弃清单 + 人工确认」作为清除判定,避免一行永久卡住整个分区。
|
3. `C-8` 允许以「放弃清单 + 人工确认」作为清除判定,避免一行永久卡住整个分区。
|
||||||
|
|
||||||
两个边界要说清:`MISSING_ROW`(信箱行不存在)是**确定性结论**,立即放弃,不受 `R` 保护;`R` 仍然**不保护重放窗口**——`R` 与 `R_keep` 只要求 `R ≤ R_keep`,重放窗口的唯一保证来源是 `C-7`。
|
两个边界要说清:`MISSING_ROW`(信箱行不存在)是**确定性结论**,立即放弃,不受 `R` 保护;`R` 只要求 `R ≤ R_keep`,原文保留期的唯一约束来源是 `C-7`。
|
||||||
|
|
||||||
重放窗口的保护只有两条路:约定保留期(`C-6` + `C-7`,目标前提),或另设原文保留通道(`G-REPLAY-CHANNEL`)。若库方清除语义是「打标即可清除」,则当天打标的原文当天即可被清除,增大 `R` 无效。
|
若库方清除语义是「打标即可清除」,则清除前提(`C-6`~`C-8`)不成立,必须与库方另定保留期;增大 `R` 无效。
|
||||||
|
|
||||||
## 7. 日计划快照与请求匹配
|
## 7. 日计划快照与请求匹配
|
||||||
|
|
||||||
@@ -226,10 +208,10 @@ LIMIT PARAM:msgx.pipeline.backfill-batch
|
|||||||
|
|
||||||
`SCHD-DNLD` 与 `SCHD-RESP` 共用 `ScheduleProcessor.applyScheduleRecords`:
|
`SCHD-DNLD` 与 `SCHD-RESP` 共用 `ScheduleProcessor.applyScheduleRecords`:
|
||||||
|
|
||||||
1. **重放判定**:`PROC_STATE` 已存在成功终态 → 幂等成功,仅追加留痕,不重复写入。
|
1. **重复处理判定**:`PROC_STATE` 已存在成功终态 → 幂等成功,仅追加留痕,不重复写入。
|
||||||
2. **整包校验**:声明记录数、航班标识与运营日推导等校验失败 → 整包 `DEAD(PROTOCOL)`,不写半包,既有状态保持不变。
|
2. **整包校验**:声明记录数、航班标识与运营日推导等校验失败 → 整包 `DEAD(PROTOCOL)`,不写半包,既有状态保持不变。
|
||||||
3. **事务写入**:锁内按 `FLID` 点查归属日,发现同一航班跨运营日即整包回滚并 `DEAD(PROTOCOL)`;通过后合并写主表与资源明细。报文未携带的航班不因本次日计划报文被删除。
|
3. **分批写入**:锁内按 `FLID` 点查归属日,发现同一航班跨运营日即整包回滚并 `DEAD(PROTOCOL)`;通过后分批合并写主表与资源明细,每批一个事务(状态变更 + 待发事件,`INV-17b`)。快照里没有的航班删除:标记已删除、登记删除事件、从 Redis 投影移除(`INV-15b`)。
|
||||||
4. **提交结果**:同一事务保存 `KAFKA:schd` / `KAFKA:msg` 事件、置消息 `SUCCEEDED` 并预登记回填意图;提交后信箱回填由扫描承接,留痕在事务外追加。
|
4. **提交结果**:整包完成后在同一事务置消息 `SUCCEEDED` 并预登记回填意图;提交后信箱回填由扫描承接,留痕在事务外追加。处理失败不标记已处理,下轮整包重新处理。
|
||||||
|
|
||||||
字段缺失与清空语义、运营日规则见「航班域」。
|
字段缺失与清空语义、运营日规则见「航班域」。
|
||||||
|
|
||||||
@@ -299,12 +281,10 @@ PENDING → SENT → DONE
|
|||||||
|
|
||||||
| 中断位置 | 重启后的判定 | 恢复动作 |
|
| 中断位置 | 重启后的判定 | 恢复动作 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 已落信、未入队 | 信箱行位于应扫描的 ID 范围且 PG 无记录(不以处理标记为判据) | 重扫补建入队记录 |
|
| 已落信、未入队 | 信箱行处理标记为空且 PG 无记录 | 重扫补建登记记录 |
|
||||||
| 水位卡在空洞 | `HOLE_SINCE` 有值且未超过 `PARAM:msgx.pipeline.max-commit-delay` | 等待;超期后放行空洞本身并继续推进 |
|
|
||||||
| 事务执行中 | PG 无该消息终态 | 事务整体回滚,按 `PENDING` 重新处理 |
|
| 事务执行中 | PG 无该消息终态 | 事务整体回滚,按 `PENDING` 重新处理 |
|
||||||
| 事务已提交、标记未写 | 终态行仍持有回填意图 | 仅补写标记;业务处理结果保持不变 |
|
| 事务已提交、标记未写 | 终态行仍持有回填意图 | 仅补写标记;业务处理结果保持不变 |
|
||||||
| 标记写入中途 | 标记仍为空 | 重新写入;重复写入同一值无副作用 |
|
| 标记写入中途 | 标记仍为空 | 重新写入;重复写入同一值无副作用 |
|
||||||
| 兼容入口已入队、水位未追平 | PG 已有该 ID 的记录 | 轮询读到该行时主键幂等,水位照常推进 |
|
|
||||||
| 回填时信箱行已不存在 | 写入 0 行且信箱行不存在 | 立即放弃自动重试(`MISSING_ROW`)并告警;放弃不等于标记已确认,仍需人工对账 |
|
| 回填时信箱行已不存在 | 写入 0 行且信箱行不存在 | 立即放弃自动重试(`MISSING_ROW`)并告警;放弃不等于标记已确认,仍需人工对账 |
|
||||||
| `RECEIVED_AT` 为 NULL | 超期分支以本地 `ENQUEUED_AT` 判定,不受库方时钟与 NULL 影响 | 按 `R` 超期强补写;未超期则按退避重试 |
|
| `RECEIVED_AT` 为 NULL | 超期分支以本地 `ENQUEUED_AT` 判定,不受库方时钟与 NULL 影响 | 按 `R` 超期强补写;未超期则按退避重试 |
|
||||||
| 投递目标已接受、`SENT` 未置 | 事件仍 `PENDING` | 允许重发,消费方按事件身份去重 |
|
| 投递目标已接受、`SENT` 未置 | 事件仍 `PENDING` | 允许重发,消费方按事件身份去重 |
|
||||||
@@ -316,40 +296,36 @@ PENDING → SENT → DONE
|
|||||||
|
|
||||||
**通则**(对本系统所有持久对象适用)
|
**通则**(对本系统所有持久对象适用)
|
||||||
|
|
||||||
- **时间不构成清除依据**:到期只是必要条件,**终局证据才是充分条件**(共享库见 `C-8`,航班见 `D1`)。
|
- **时间不构成清除依据**:到期只是必要条件,**终局证据才是充分条件**(共享库见 `C-8`,航班见 `INV-28`)。
|
||||||
- **归档不是终点**:归档目标是新的无界集合,必须有独立保留期与清除作业 `G-HST-RETENTION`,否则只是把容量问题从热表移到冷表。
|
|
||||||
- **证据不随清除消失**:清除所依赖的证据(如 `C-8` 引用的回填放弃清单,本期承诺见 `C-16`)在其覆盖的信箱边界被清除前必须保持可查。
|
- **证据不随清除消失**:清除所依赖的证据(如 `C-8` 引用的回填放弃清单,本期承诺见 `C-16`)在其覆盖的信箱边界被清除前必须保持可查。
|
||||||
- **证据缺失或结果不明时按最保守处置**:航班清理为删 0 条(`D1`)。
|
- **证据缺失或结果不明时按最保守处置**:航班清理为删 0 条(`INV-28`)。
|
||||||
|
|
||||||
**逐对象生命周期**(保留期取值一律见 [reference.md](reference.md))
|
**逐对象生命周期**(保留期取值一律见 [reference.md](reference.md))
|
||||||
|
|
||||||
| 对象 | 终局判据 | 归档目标 | 清除证据 | 执行方 | 偏差 |
|
| 对象 | 终局判据 | 归档目标 | 清除证据 | 执行方 | 偏差 |
|
||||||
|---|---|---|---|---|---|
|
|---|---|---|---|---|---|
|
||||||
| 共享信箱 `CMINMSGS` 原文 | 处理标记 / 回填放弃清单 | 库方历史表(`C-9` 方案 B) | `C-8` | 库方 | 契约未确认(`Q6`/`Q7`/`Q9`) |
|
| 共享信箱 `CMINMSGS` 原文 | 处理标记 / 回填放弃清单 | — | `C-8` | 库方 | 契约未确认(`Q7`/`Q9`) |
|
||||||
| `FLIGHT_SCHD` + 资源明细 | 判史规则 | 历史存储 | 归档确认 + 版本复查 | 我们 | — |
|
| `FLIGHT_SCHD` + 资源明细 | 判史规则 | 历史存储 | 历史写入确认 + 版本复查 | 我们 | — |
|
||||||
| 航班历史存储 | 保留期 | — | — | 我们 | `G-FLIGHT-HIST-RETENTION` |
|
| 航班历史存储 | 保留期 | — | — | 我们 | `G-FLIGHT-HIST-RETENTION` |
|
||||||
| `SCHD_SNAP_LOG` | 保留期 | 无(本地可重建) | 无 | 我们 | — |
|
| `SCHD_SNAP_LOG` | 保留期 | 无(本地可重建) | 无 | 我们 | — |
|
||||||
| `MSG_EVENT` 已发送行 | `SENT` | 无 | 无 | 我们 | — |
|
| `MSG_EVENT` 已发送行 | `SENT` | 无 | 无 | 我们 | — |
|
||||||
| `PROC_STATE` 终态行 | 见下 | `PROC_STATE_HST` | 回填了结 | 我们 | `G-PROC-HST` |
|
| `PROC_STATE` 终态行 | 见下 | 无(到期直接删除) | 回填了结 | 我们 | `G-PROC-CLEANUP` |
|
||||||
| `PROC_STATE_HST` | 保留期 | — | — | 我们 | `G-HST-RETENTION` |
|
|
||||||
| `REQ_TRACK` 关闭态行 | 保留期 | 无 | 无 | 我们 | `G-REQ-TRACK-RETENTION` |
|
| `REQ_TRACK` 关闭态行 | 保留期 | 无 | 无 | 我们 | `G-REQ-TRACK-RETENTION` |
|
||||||
|
|
||||||
原文副本是**条件对象**:仅当库方清除语义不满足 `C-6` 时才成立(`G-REPLAY-CHANNEL`、`CLM-5`),窗口与 `R_keep` 相同,落在自有 PG。
|
**处理记录到期清理**(`INV-25`)
|
||||||
|
|
||||||
**处理终态归档**(`PROC_STATE` → `PROC_STATE_HST`)
|
候选 = 终态 **且** 回填已了结 **且** 终局后超过保留期(基准是 `UPDATED_AT`:终态与了结都推进它,了结后不再更新)。两处不可省:
|
||||||
|
|
||||||
候选 = 终态 **且** 回填已了结 **且** 终局后经过归档阈值(基准是 `UPDATED_AT`:终态与了结都推进它,了结后不再更新)。两处不可省:
|
- **回填已了结** = `BACKFILL_AT` 非空,或已放弃 **且经人工对账**。放弃行不写标记,是 `C-8` 的清除授权证据,未对账前不得删除。
|
||||||
|
- **写入前复查** = `DEAD` 可被人工重放改回 `PENDING`。人工重放走 `MessageLifecycleGate`、不取 `PIPELINE_LOCK`,因此该锁不构成复查依据:删除在同一事务内按候选时的 `STATE` 条件执行;影响 0 行即整体回滚、该行跳过。重放先一步改回 `PENDING` 时谓词不匹配,天然互斥。批量删除不得持 `PIPELINE_LOCK`——那会阻塞主泵 FIFO,与「作业不使到期消息饥饿」冲突。
|
||||||
|
|
||||||
- **回填已了结** = `BACKFILL_AT` 非空,或已放弃 **且经人工对账**。放弃行不写标记,是 `C-8` 的清除授权证据,未对账前不得归档。
|
清理范围只含「终态且已回填」;保留期内同身份去重成立(`INV-9`),保留期过后同身份消息按新消息处理(去重记忆期 = 保留期,见 [specification.md](specification.md)「契约数值」)。
|
||||||
- **写入前复查** = `DEAD` 可被人工重放改回 `PENDING`。人工重放走 `MessageLifecycleGate`、不取 `PIPELINE_LOCK`,因此该锁不构成复查依据:归档在同一事务内先 `INSERT INTO PROC_STATE_HST … SELECT`,再按候选时的 `STATE` 条件写主表;影响 0 行即整体回滚、该行跳过。重放先一步改回 `PENDING` 时谓词不匹配,天然互斥。批量归档不得持 `PIPELINE_LOCK`——那会阻塞主泵 FIFO,与「作业不使到期消息饥饿」冲突。
|
|
||||||
|
|
||||||
归档范围只含终态;归档后仍须保留业务去重能力(`INV-9`)——去重记忆期长于工作状态在线期,实现取「主表保留去重影子行」:主行置 `STATE='ARCHIVED'`、只留 `IDENTITY_KEY` 与 `MSG_ID`,`IDENTITY_KEY` 唯一约束留在主表不动。队头推进、`backlog()` 与回填扫描的谓词显式排除 `ARCHIVED`,不靠状态包含列表隐式过滤。
|
**时间常数排序**:`R ≤ R_keep`、放弃清单可见期 ≥ `R_keep` 两个下界关系的定义与理由见 [specification.md](specification.md)「契约数值」,本文件不复述。只补一条实现口径:保留期计的是**终局之后**的时间,不是入队之后——终态行未了结回填时不进入候选。
|
||||||
|
|
||||||
**时间常数排序**:`R ≤ R_keep`、去重记忆期 ≥ `R_keep`、放弃清单可见期 ≥ `R_keep` 三个下界关系的定义与理由见 [specification.md](specification.md)「契约数值」,本文件不复述。只补一条实现口径:归档阈值计的是**终局之后**的时间,不是入队之后——终态行未了结回填时不进入候选。
|
|
||||||
|
|
||||||
**其余清理**
|
**其余清理**
|
||||||
|
|
||||||
- **航班历史清理**:按 [reference.md](reference.md) 的历史判据选候选(含 `DELETED`),先成功归档再删除;语义与红线见「航班域」与 `D1`。
|
- **航班历史清理**:按 [reference.md](reference.md) 的历史判据选候选(含 `DELETED`),先成功写入历史存储再删除;语义与红线见「航班域」与 `INV-28`。
|
||||||
- **留痕清理**:`SCHD_SNAP_LOG` 按保留期与 `(SCOPE_END, RECV_AT)` 删除,不依赖历史存储开关。
|
- **留痕清理**:`SCHD_SNAP_LOG` 按保留期与 `(SCOPE_END, RECV_AT)` 删除,不依赖历史存储开关。
|
||||||
- **出站事件清理**:见「事件清理」。
|
- **出站事件清理**:见「事件清理」。
|
||||||
|
|
||||||
@@ -363,18 +339,18 @@ PENDING → SENT → DONE
|
|||||||
- 处理延迟秒级可接受;航班可见性延迟不劣于现役(轮询间隔 + 聚合周期秒级)。
|
- 处理延迟秒级可接受;航班可见性延迟不劣于现役(轮询间隔 + 聚合周期秒级)。
|
||||||
- 因此:不引入多实例并行、分布式锁、分区表;用单行锁与单线程换确定性。
|
- 因此:不引入多实例并行、分布式锁、分区表;用单行锁与单线程换确定性。
|
||||||
|
|
||||||
容量假设变化时,需要重新评估的项:批次大小与轮询间隔、聚合周期与批上限、指标取数口径(`backlog()` 是 `PROC_STATE` 聚合;`G-PROC-HST`)、以及 `MSG_EVENT` 保留期。
|
容量假设变化时,需要重新评估的项:批次大小与轮询间隔、聚合周期与批上限、指标取数口径(`backlog()` 是 `PROC_STATE` 聚合)、以及 `MSG_EVENT` 保留期。
|
||||||
|
|
||||||
## 11. 航班域:权威模型与合并写入语义
|
## 11. 航班域:权威模型与合并写入语义
|
||||||
|
|
||||||
本章是航班状态的唯一现行设计规范。其他各章只描述管道机制,不重复定义航班域规则。
|
本章是航班状态的唯一现行设计规范。其他各章只描述管道机制,不重复定义航班域规则。
|
||||||
|
|
||||||
系统从共享 MySQL 信箱接收 SIS/AODB 报文,把结果合并到自有 PostgreSQL 中的航班当前态,再通过 outbox 投递 Kafka。共享信箱和 Kafka 都不是状态权威,也不在本地事务的提交范围内。
|
系统从共享 MySQL 信箱接收 SIS/AODB 报文,把结果合并到自有 PostgreSQL 中的航班当前态并同步写 Redis 投影,再通过 outbox 投递 Kafka。共享信箱、Redis 投影和 Kafka 都不是状态权威;Redis 投影写在处理完成之前(`INV-23`)。
|
||||||
|
|
||||||
- `FLID` 是航班实例的唯一标识;不得由航班号、日期或资源号推断身份。
|
- `FLID` 是航班实例的唯一标识;不得由航班号、日期或资源号推断身份。
|
||||||
- `FLIGHT_SCHD` 及其明细表是唯一权威当前态;展示视图只读,不能作为写入或对账来源(`INV-11`)。
|
- `FLIGHT_SCHD` 及其明细表是唯一权威当前态;Redis 投影与展示视图只读,不能作为写入或对账来源(`INV-11b`)。
|
||||||
- 单活动主泵按信箱 FIFO 推进。事务内 `PIPELINE_LOCK` 只串行化本地状态提交,不替代选主或消息认领。
|
- 单活动主泵按信箱 FIFO 推进。事务内 `PIPELINE_LOCK` 只串行化本地状态提交,不替代选主或消息认领。
|
||||||
- 状态写入、outbox 事件、处理终态和回填意图在同一 PostgreSQL 事务中提交(`INV-17`);回填与 Kafka 投递在提交后独立重试。
|
- 状态变更与 outbox 事件在同一 PostgreSQL 事务中提交;处理终态与回填意图在同一事务中提交、且晚于 Redis 投影写成功(`INV-17b`);回填与 Kafka 投递在提交后独立重试。
|
||||||
|
|
||||||
### 11.1 权威模型
|
### 11.1 权威模型
|
||||||
|
|
||||||
@@ -385,7 +361,6 @@ PENDING → SENT → DONE
|
|||||||
| `FLIGHT_ROUTE_POINT` | ROUT 与 ERUT 两类路线点,使用 `ROUTE_KIND` 区分;主键应包含该列,避免两类路线的序号冲突。 |
|
| `FLIGHT_ROUTE_POINT` | ROUT 与 ERUT 两类路线点,使用 `ROUTE_KIND` 区分;主键应包含该列,避免两类路线的序号冲突。 |
|
||||||
| `PROC_STATE` | 信箱消息的处理终态、业务身份幂等记录,以及回填事实(`RECEIVED_AT` / `BACKFILL_*`)。 |
|
| `PROC_STATE` | 信箱消息的处理终态、业务身份幂等记录,以及回填事实(`RECEIVED_AT` / `BACKFILL_*`)。 |
|
||||||
| `MSG_EVENT` | 事务 outbox,承载整态投影、变更通知和删除 tombstone。 |
|
| `MSG_EVENT` | 事务 outbox,承载整态投影、变更通知和删除 tombstone。 |
|
||||||
| `INBOX_CURSOR` | 共享信箱消费水位(读取进度,与处理标记互不替代)。 |
|
|
||||||
| `SCHD_SNAP_LOG` | 日计划处理留痕,只追加、可重建,不参与状态决策。 |
|
| `SCHD_SNAP_LOG` | 日计划处理留痕,只追加、可重建,不参与状态决策。 |
|
||||||
|
|
||||||
### 11.2 航班身份与运营日
|
### 11.2 航班身份与运营日
|
||||||
@@ -445,21 +420,19 @@ PENDING → SENT → DONE
|
|||||||
|
|
||||||
## 12. 航班域:合并、删除与生命周期
|
## 12. 航班域:合并、删除与生命周期
|
||||||
|
|
||||||
本章的领域规则只描述「合并成什么态」;决策纯度、事务边界与落库职责见「消息、身份与决策」与 `INV-17`(`US-03`)。
|
本章的领域规则只描述「合并成什么态」;决策纯度、事务边界与落库职责见「消息、身份与决策」与 `INV-17b`(`US-03`)。
|
||||||
|
|
||||||
### 12.1 SCHD 日计划
|
### 12.1 SCHD 日计划
|
||||||
|
|
||||||
SCHD DNLD/RESP 在整包校验通过后,逐条将报文携带的航班写入当前态。日计划只更新或创建其携带的 `FLID`,**不会因其他航班未出现在本次报文中而删除任何记录**(`INV-15`);SIS 同向(`SIS:3.16-note-1` 要求子系统自行保留前一日延误航班)。
|
SCHD DNLD/RESP 在整包校验通过后,分批将报文携带的航班写入当前态,每批一个事务;快照里没有的航班删除:标记已删除、登记删除事件、从 Redis 投影移除(`INV-15b`)。日计划就是主动与 AODB 全量同步一次,以 AODB 下发的数据为准。
|
||||||
|
|
||||||
日计划在重叠字段上可以覆盖当前动态值;未携带的字段按合并规则保留,显式清空才清除。每个成功写入的航班推进 `STATE_VERSION`(`INV-13`),并在同一事务登记 `KAFKA:schd` 与 `KAFKA:msg` 事件。
|
日计划里某航班没携带的字段,视为 AODB 已删除该值,本地同步清除(`C-26`)。每个成功写入的航班推进 `STATE_VERSION`(`INV-13`),并在同一事务登记 `KAFKA:schd` 与 `KAFKA:msg` 事件。
|
||||||
|
|
||||||
**字段缺失语义与外部规范冲突**:SIS 要求以 AODB 最新数据覆盖本地(`SIS:1.6.2`),且未发送的可选字段表示应删除本地值(`C-26`、`Q13`),与上面的「未携带字段保留」相反。确认前两条并存,不得据本节推定已与上游对齐。
|
消息重复处理由 `PROC_STATE` 的消息 ID 与 `IDENTITY_KEY` 控制;已成功提交的消息不得再次写入或重复登记事件。整包校验失败或运营日冲突时,整包不落地(`INV-19`)。
|
||||||
|
|
||||||
消息重放由 `PROC_STATE` 的消息 ID 与 `IDENTITY_KEY` 控制;已成功提交的消息不得再次写入或重复登记事件。整包校验失败或运营日冲突时,整包不落地(`INV-19`)。
|
|
||||||
|
|
||||||
### 12.2 动态运行事件(FLOP)
|
### 12.2 动态运行事件(FLOP)
|
||||||
|
|
||||||
FLOP 只修改报文表达的字段或集合,其余状态保持不变;目标形态与合并规则见「字段与集合」。`STYP` 必须命中下表白名单,未知值转 `FAILED(UNSUPPORTED)`,不得进入通用合并。除表内方向拒绝项外,已确认的动态更新在同一事务推进 `STATE_VERSION`、登记 `KAFKA:msg` 与 `KAFKA:schd`、提交处理终态与回填意图;同一消息重试不得重复产生业务效果(`INV-17`、`INV-20`)。
|
FLOP 只修改报文表达的字段或集合,其余状态保持不变;目标形态与合并规则见「字段与集合」。`STYP` 必须命中下表白名单,未知值按不支持类型跳过留档(`US-03` AC2),不得进入通用合并。已确认的动态更新在同一事务推进 `STATE_VERSION`、登记 `KAFKA:msg` 与 `KAFKA:schd`、提交处理终态与回填意图;同一消息重复处理不得重复产生业务效果(`INV-17b`、`INV-20b`)。
|
||||||
|
|
||||||
逐类语义以 SIS 的字段表、空标签规则与 Processing Exceptions 为准;下表每一行都必须有一条回归用例钉住「输入与前态 → 目标状态 → 终态与事件」。
|
逐类语义以 SIS 的字段表、空标签规则与 Processing Exceptions 为准;下表每一行都必须有一条回归用例钉住「输入与前态 → 目标状态 → 终态与事件」。
|
||||||
|
|
||||||
@@ -470,9 +443,9 @@ FLOP 只修改报文表达的字段或集合,其余状态保持不变;目标
|
|||||||
| `SIS:3.21` | `BOTM` | `BOTM` 标量;非空时设置登机状态 | 空 = 清除登机时间并重置登机状态 |
|
| `SIS:3.21` | `BOTM` | `BOTM` 标量;非空时设置登机状态 | 空 = 清除登机时间并重置登机状态 |
|
||||||
| `SIS:3.22` | `CHOT` | `CHOT` 集合 | 集合按完整结果替换;元素内 `CHTM` 空 = 删除该轮挡时间 |
|
| `SIS:3.22` | `CHOT` | `CHOT` 集合 | 集合按完整结果替换;元素内 `CHTM` 空 = 删除该轮挡时间 |
|
||||||
| `SIS:3.23` | `FLTY` | `FLTY` 标量 | 字段为 M,未写明空语义 |
|
| `SIS:3.23` | `FLTY` | `FLTY` 标量 | 字段为 M,未写明空语义 |
|
||||||
| `SIS:3.24` | `CKDT` | `CKDT` 集合 | 空 `<CKDT CKNO="0">` = 现无柜台分配;**AODB 方向报文必须拒绝** |
|
| `SIS:3.24` | `CKDT` | `CKDT` 集合 | 空 `<CKDT CKNO="0">` = 现无柜台分配;AODB 实际会发,照常接收处理(`US-05` AC3) |
|
||||||
| `SIS:3.25` | `CLDT` | `CLDT` 集合 | 空 `<CLDT CLNO="0">` = 现无转盘分配;**AODB 方向报文必须拒绝** |
|
| `SIS:3.25` | `CLDT` | `CLDT` 集合 | 空 `<CLDT CLNO="0">` = 现无转盘分配;AODB 实际会发,照常接收处理(`US-05` AC3) |
|
||||||
| `SIS:3.26` | `CHDT` | `CHDT` 集合 | 空 `<CHDT CHNO="0">` = 现无滑槽分配;**AODB 方向报文必须拒绝** |
|
| `SIS:3.26` | `CHDT` | `CHDT` 集合 | 空 `<CHDT CHNO="0">` = 现无滑槽分配;AODB 实际会发,照常接收处理(`US-05` AC3) |
|
||||||
| `SIS:3.27` | `CNCL` | `CNCL` 标量 | 空 = **撤销**上一次取消(不是清空时间) |
|
| `SIS:3.27` | `CNCL` | `CNCL` 标量 | 空 = **撤销**上一次取消(不是清空时间) |
|
||||||
| `SIS:3.28` | `ESTT` | `ESTT` 标量 | 空 = 删除预计时间 |
|
| `SIS:3.28` | `ESTT` | `ESTT` 标量 | 空 = 删除预计时间 |
|
||||||
| `SIS:3.29` | `FDEL` | 走删除路径(「删除与重建」) | 恒为空标签 |
|
| `SIS:3.29` | `FDEL` | 走删除路径(「删除与重建」) | 恒为空标签 |
|
||||||
@@ -480,18 +453,18 @@ FLOP 只修改报文表达的字段或集合,其余状态保持不变;目标
|
|||||||
| `SIS:3.31` | `FINT` | `FINT` 标量 | 空 = 删除最终时间 |
|
| `SIS:3.31` | `FINT` | `FINT` 标量 | 空 = 删除最终时间 |
|
||||||
| `SIS:3.32` | `FLIN` | `FLIN` 标量 | 字段为 M,未写明空语义 |
|
| `SIS:3.32` | `FLIN` | `FLIN` 标量 | 字段为 M,未写明空语义 |
|
||||||
| `SIS:3.33` | `FRET` | `FRET`(`REID`),当前未映射(`G-FLOP-UNMAPPED`) | 空 = 清除返航标志 |
|
| `SIS:3.33` | `FRET` | `FRET`(`REID`),当前未映射(`G-FLOP-UNMAPPED`) | 空 = 清除返航标志 |
|
||||||
| `SIS:3.34` | `GTDT` | `GTDT` 集合 | 空 `<GTDT GTNO="0">` = 现无登机门分配;`GOTM`/`GCTM` 缺失 = 未分配开放/关闭时间;**AODB 方向报文必须拒绝** |
|
| `SIS:3.34` | `GTDT` | `GTDT` 集合 | 空 `<GTDT GTNO="0">` = 现无登机门分配;`GOTM`/`GCTM` 缺失 = 未分配开放/关闭时间;AODB 实际会发,照常接收处理(`US-05` AC3) |
|
||||||
| `SIS:3.35` | `LACL` | `LACL` 标量;非空时设置最后通知状态 | 空 = 清除最后通知时间并重置最后通知状态 |
|
| `SIS:3.35` | `LACL` | `LACL` 标量;非空时设置最后通知状态 | 空 = 清除最后通知时间并重置最后通知状态 |
|
||||||
| `SIS:3.36` | `MAXP` | `MAXP` 标量 | 空 = 删除最大载客数 |
|
| `SIS:3.36` | `MAXP` | `MAXP` 标量 | 空 = 删除最大载客数 |
|
||||||
| `SIS:3.37` | `HNAG` | `FHAG`/`PHAG`/`MHAG` 标量 | `FHAG` 空 = 删除该代理;`MHAG` 可缺席 |
|
| `SIS:3.37` | `HNAG` | `FHAG`/`PHAG`/`MHAG` 标量 | `FHAG` 空 = 删除该代理;`MHAG` 可缺席 |
|
||||||
| `SIS:3.38` | `PSDT` | `PSDT` 集合 | 空 `<PSDT PSNO="0">` = 现无机位分配;**AODB 方向报文必须拒绝** |
|
| `SIS:3.38` | `PSDT` | `PSDT` 集合 | 空 `<PSDT PSNO="0">` = 现无机位分配;AODB 实际会发,照常接收处理(`US-05` AC3) |
|
||||||
| `SIS:3.39` | `RENO` | `RENO` 标量 | 空 = 清除注册号 |
|
| `SIS:3.39` | `RENO` | `RENO` 标量 | 空 = 清除注册号 |
|
||||||
| `SIS:3.40` | `ROUT` | `ROUT` 集合 | `SCAT`/`SCDT` 分别对起点/终点缺席;RMS 只保留 4 条(离港取前 4、到港取后 4)且不保存 `SCAT`/`SCDT` |
|
| `SIS:3.40` | `ROUT` | `ROUT` 集合 | `SCAT`/`SCDT` 分别对起点/终点缺席;RMS 只保留 4 条(离港取前 4、到港取后 4)且不保存 `SCAT`/`SCDT` |
|
||||||
| `SIS:3.41` | `TAOP` | `TAOP`/`TAFL`/`TAID` 标量 | 任一为空 = 该到达航班的经停连接断开 |
|
| `SIS:3.41` | `TAOP` | `TAOP`/`TAFL`/`TAID` 标量 | 任一为空 = 该到达航班的经停连接断开 |
|
||||||
| `SIS:3.42` | `TRML` | `TRML` 标量 | 空 = 删除航站楼 |
|
| `SIS:3.42` | `TRML` | `TRML` 标量 | 空 = 删除航站楼 |
|
||||||
| `SIS:3.43` | `VIPP` | `VIPP`/`VIPR` 标量 | 空 = 删除;SIS 另要求 RMS 忽略 `VIPP`(忽略事件还是忽略字段,SIS 未写明,按 `Q8` 对拍确认) |
|
| `SIS:3.43` | `VIPP` | `VIPP`/`VIPR` 标量 | 空 = 删除;SIS 另要求 RMS 忽略 `VIPP`(忽略事件还是忽略字段,SIS 未写明,按 `Q8` 对拍确认) |
|
||||||
|
|
||||||
**方向约束**:`SIS:3.24`、`SIS:3.25`、`SIS:3.26`、`SIS:3.34`、`SIS:3.38` 五节明确「RMS will reject this message if received from AODB」——柜台、转盘、滑槽、登机门、计划机位是 RMS→AODB 的分配事件。本系统只从日计划快照接受这五个集合,收到对应 FLOP 报文必须拒绝(当前实现的偏差见 `G-FLOP-DIRECTION`)。
|
**方向约束**:`SIS:3.24`、`SIS:3.25`、`SIS:3.26`、`SIS:3.34`、`SIS:3.38` 五节写的是 RMS→AODB 方向。需求已定案:这五类资源分配报文 AODB 实际会发,照常接收处理(`US-05` AC3);与 AODB 的核对确认是实施任务。
|
||||||
|
|
||||||
**SIS 未定义但 legacy 处理的子类型**:`ABTM`、`DELY`、`PADT`、`FTSS`、`STND`、`BDPB`、`REMC`。它们在 `XSD` 的 `FLOP` 段里是普通字段或集合,没有独立事件节;legacy 按 `STYP` 命中它们处理,说明真实流量可能存在 SIS 未记载的子类型。其报文形态与是否存在必须以真实报文确认(`Q8`),不得据 legacy 行为直接定案。
|
**SIS 未定义但 legacy 处理的子类型**:`ABTM`、`DELY`、`PADT`、`FTSS`、`STND`、`BDPB`、`REMC`。它们在 `XSD` 的 `FLOP` 段里是普通字段或集合,没有独立事件节;legacy 按 `STYP` 命中它们处理,说明真实流量可能存在 SIS 未记载的子类型。其报文形态与是否存在必须以真实报文确认(`Q8`),不得据 legacy 行为直接定案。
|
||||||
|
|
||||||
@@ -504,14 +477,13 @@ FLOP 只修改报文表达的字段或集合,其余状态保持不变;目标
|
|||||||
### 12.3 删除与重建
|
### 12.3 删除与重建
|
||||||
|
|
||||||
FDEL 是业务删除入口:仅在 `ACTIVE → DELETED` 时推进版本、保留明细并与 tombstone 同事务登记;重复 FDEL 或不存在的航班按幂等成功处理。
|
FDEL 是业务删除入口:仅在 `ACTIVE → DELETED` 时推进版本、保留明细并与 tombstone 同事务登记;重复 FDEL 或不存在的航班按幂等成功处理。
|
||||||
|
物理删除仅由独立历史清理在历史写入成功后执行(`INV-28`)。快照里没有的航班删除(`INV-15b`);FDEL 仍是最先的删除入口。清理前需要登记一次 tombstone;已经 FDEL 的记录不重复发出。
|
||||||
物理删除仅由独立历史清理在归档成功后执行(`D1`)。日计划报文不是删除依据(`INV-15`)。若未经 FDEL 而由生命周期清理,清理前需要登记一次 tombstone;已经 FDEL 的记录不重复发出。
|
|
||||||
|
|
||||||
ADFT 的字段缺失语义尚待上游确认。在确认前采用保守的 Set-only 规则:出现字段可更新,缺失字段不清空;不得把它当成日计划或动态全量替换。新建 ADFT 若带可解析的 `SODT`,按同一运营日规则计算 `OPERATION_DAY`;否则保留为 `NULL`。
|
ADFT 的字段缺失语义尚待上游确认。在确认前采用保守的 Set-only 规则:出现字段可更新,缺失字段不清空;不得把它当成日计划或动态全量替换。新建 ADFT 若带可解析的 `SODT`,按同一运营日规则计算 `OPERATION_DAY`;否则保留为 `NULL`。
|
||||||
|
|
||||||
主/共享航班级联:删除共享航班时重算主航班 `MAFL`(见「主/共享投影」)并向主航班通知;删除主航班时级联删除其子共享关联并发出删除通知;主/共享关系必须一次原子变更,不出现主已删、子残留的半状态。共享航班增量通常只更新并通知主航班,不直接发共享通知。这些语义同样约束 FDEL 之外的生命周期清理。主/共享关联的增删按 `FLID` 做值比较,不使用引用比较。
|
主/共享航班级联:删除共享航班时重算主航班 `MAFL`(见「主/共享投影」)并向主航班通知;删除主航班时级联删除其子共享关联并发出删除通知;主/共享关系必须一次原子变更,不出现主已删、子残留的半状态。共享航班增量通常只更新并通知主航班,不直接发共享通知。这些语义同样约束 FDEL 之外的生命周期清理。主/共享关联的增删按 `FLID` 做值比较,不使用引用比较。
|
||||||
|
|
||||||
本章的原子级联不回发 EROR,与 SIS 的删除顺序要求相反;取舍见 `C-25`、`Q14`。
|
本章的原子级联不回发 EROR(`C-25`、`Q14` 已定案)。
|
||||||
|
|
||||||
### 12.4 Kafka 与读取
|
### 12.4 Kafka 与读取
|
||||||
|
|
||||||
@@ -560,7 +532,7 @@ ADFT 的字段缺失语义尚待上游确认。在确认前采用保守的 Set-o
|
|||||||
|
|
||||||
### 13.3 结构与合并语义
|
### 13.3 结构与合并语义
|
||||||
|
|
||||||
`REF_MASTER` 是对业务暴露的有效参考数据视图,逻辑身份为 `(RTYPE, RKEY)`;普通类别的 `RKEY` 见上表,`RSTA` 的身份必须同时包含 `RTYP` 与 `RSID`。记录保存消息来源、消息批次、刷新时间与按 SIS 标签名组织的字段载荷;重复字段保留输入顺序并表示为有序数组。物理列与批次暂存方式在 `Q8` 定案,定案前不得据本节新增 DDL。
|
`REF_MASTER` 是对业务暴露的有效参考数据视图,逻辑身份为 `(RTYPE, RKEY)`;普通类别的 `RKEY` 见上表,`RSTA` 的身份必须同时包含 `RTYP` 与 `RSID`。记录保存消息来源、消息批次、刷新时间与按 SIS 标签名组织的字段载荷;重复字段保留输入顺序并表示为有序数组。参考数据保存在独立的数据表中,admin-api 直接读取(`C-31`)。
|
||||||
|
|
||||||
- **13 类参考数据**:`DNLD`/`RESP` 是类别全量,整批校验通过后原子发布;`ADD`/`UPD`/`DEL` 是单条全字段增量,按 `(RTYPE, RKEY)` 处理。全量替换只作用于消息指定的同一 `RTYPE`。
|
- **13 类参考数据**:`DNLD`/`RESP` 是类别全量,整批校验通过后原子发布;`ADD`/`UPD`/`DEL` 是单条全字段增量,按 `(RTYPE, RKEY)` 处理。全量替换只作用于消息指定的同一 `RTYPE`。
|
||||||
- **资源状态**:`RSTA-DNLD` 是单条状态更新,按 (`RTYP`, `RSID`) 覆盖;`RSTA-RESP` 是请求返回的多条记录。两者都不以“本包未出现”为理由删除其他资源状态。
|
- **资源状态**:`RSTA-DNLD` 是单条状态更新,按 (`RTYP`, `RSID`) 覆盖;`RSTA-RESP` 是请求返回的多条记录。两者都不以“本包未出现”为理由删除其他资源状态。
|
||||||
@@ -584,4 +556,4 @@ SIS 声明的上游忽略与截断口径(`SIS:3.1`/`SIS:3.2`/`SIS:3.4`/`SIS:3.
|
|||||||
- 数据方向固定为「SIS 消息 → 本网关 → 业务数据库 → admin-api」;本网关不调用 admin-api,不读取其数据库或缓存。
|
- 数据方向固定为「SIS 消息 → 本网关 → 业务数据库 → admin-api」;本网关不调用 admin-api,不读取其数据库或缓存。
|
||||||
- admin-api 只读取已提交的航班状态与 `REF_MASTER` 有效视图,不参与消息解码、合并、批次发布或处理终态判定。
|
- admin-api 只读取已提交的航班状态与 `REF_MASTER` 有效视图,不参与消息解码、合并、批次发布或处理终态判定。
|
||||||
- 开发运行时使用自有 PostgreSQL;Oracle 只有通过 `Q1` 要求的方言与集成验证后才可替代,单次部署不得同时把两库作为权威。
|
- 开发运行时使用自有 PostgreSQL;Oracle 只有通过 `Q1` 要求的方言与集成验证后才可替代,单次部署不得同时把两库作为权威。
|
||||||
- admin-api 的物理读取契约在 `Q8` 定案;共享 MySQL 始终只是信箱边界,不承载该读取模型。
|
- admin-api 直接读取本系统写入的静态参考数据表(`C-31`);共享 MySQL 始终只是信箱边界,不承载该读取模型。
|
||||||
|
|||||||
+1
-2
@@ -18,7 +18,7 @@
|
|||||||
| `msgx.pipeline.backoff-ms` | `[1000,2000,4000,8000]` | ms / 档 | 假定 | **档位数必须 = `max-attempts − 1`**,启动自检拦截错位 |
|
| `msgx.pipeline.backoff-ms` | `[1000,2000,4000,8000]` | ms / 档 | 假定 | **档位数必须 = `max-attempts − 1`**,启动自检拦截错位 |
|
||||||
| `msgx.pipeline.backoff-cap-ms` | `60000` | ms | 假定 | 单档封顶;默认表内无档触及 |
|
| `msgx.pipeline.backoff-cap-ms` | `60000` | ms | 假定 | 单档封顶;默认表内无档触及 |
|
||||||
| `msgx.pipeline.max-commit-delay` | `5m` | Duration | **假定(无依据)** | 空洞老化阈值;由 `C-2` 决定,**不可由 SIS `Expiry` 推导**(`Q2`) |
|
| `msgx.pipeline.max-commit-delay` | `5m` | Duration | **假定(无依据)** | 空洞老化阈值;由 `C-2` 决定,**不可由 SIS `Expiry` 推导**(`Q2`) |
|
||||||
| `msgx.pipeline.overdue-backfill` | `30d` | Duration | 契约(`R ≤ R_keep`) | 即 `R`:进入强补写窗口、**取消退避**的阈值;**不是兜底保证**,不保护重放窗口(`Q6`) |
|
| `msgx.pipeline.overdue-backfill` | `30d` | Duration | 契约(`R ≤ R_keep`) | 即 `R`:进入强补写窗口、**取消退避**的阈值;**不是兜底保证** |
|
||||||
| `msgx.pipeline.backfill-batch` | `100` | 条 | 假定 | 回填扫描单批条数 |
|
| `msgx.pipeline.backfill-batch` | `100` | 条 | 假定 | 回填扫描单批条数 |
|
||||||
| `msgx.pipeline.backfill-scan-period` | `30s`(代码常量,无配置键) | Duration | 现役 | 回填扫描作业周期;批次积压与单行超时会延长实际标记延迟(`CLM-9`) |
|
| `msgx.pipeline.backfill-scan-period` | `30s`(代码常量,无配置键) | Duration | 现役 | 回填扫描作业周期;批次积压与单行超时会延长实际标记延迟(`CLM-9`) |
|
||||||
| `msgx.pipeline.backfill-max-attempts` | `100` | 次 | 假定 | 单行重试的**告警阈值**;放弃判据是 `R` 超期,不是次数 |
|
| `msgx.pipeline.backfill-max-attempts` | `100` | 次 | 假定 | 单行重试的**告警阈值**;放弃判据是 `R` 超期,不是次数 |
|
||||||
@@ -49,7 +49,6 @@
|
|||||||
| `msgx.history.deleted-hours` | `48` | 假定 | 历史清理的已删除判据窗口 |
|
| `msgx.history.deleted-hours` | `48` | 假定 | 历史清理的已删除判据窗口 |
|
||||||
| `msgx.history.idle-hours` | `168` | 假定 | 历史清理的静默期判据 |
|
| `msgx.history.idle-hours` | `168` | 假定 | 历史清理的静默期判据 |
|
||||||
| `msgx.history.snap-log-retention-days` | `90` | 假定 | `SCHD_SNAP_LOG` 保留天数 |
|
| `msgx.history.snap-log-retention-days` | `90` | 假定 | `SCHD_SNAP_LOG` 保留天数 |
|
||||||
| `msgx.proc-state.archive-after` | `1d` | 假定 | 终态记录归档阈值,建议范围 1~7 天;目标表见 `G-PROC-HST`,见 `US-11` |
|
|
||||||
|
|
||||||
### 1.3 信箱与外部依赖(成组登记)
|
### 1.3 信箱与外部依赖(成组登记)
|
||||||
|
|
||||||
|
|||||||
@@ -188,10 +188,10 @@
|
|||||||
|
|
||||||
| 编号 | 要求 | 验证方式 |
|
| 编号 | 要求 | 验证方式 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| OPS-1 单实例运行 | 系统配置不完整时拒绝启动;同一时刻只允许一个实例处理消息。 | 配置错误启动失败测试;双实例同时启动测试。 |
|
| `OPS-1` | 单实例运行:系统配置不完整时拒绝启动;同一时刻只允许一个实例处理消息。 | 配置错误启动失败测试;双实例同时启动测试。 |
|
||||||
| OPS-2 可观测 | 消息积压、处理失败、发送失败、标记写回失败都有监控指标和告警。 | 故障注入触发告警;检查监控面板。 |
|
| `OPS-2` | 可观测:消息积压、处理失败、发送失败、标记写回失败都有监控指标和告警。 | 故障注入触发告警;检查监控面板。 |
|
||||||
| OPS-3 测试隔离 | 测试环境的实例使用独立的数据库、Redis、Kafka 主题,不连接生产信箱。 | 配置检查。 |
|
| `OPS-3` | 测试隔离:测试环境的实例使用独立的数据库、Redis、Kafka 主题,不连接生产信箱。 | 配置检查。 |
|
||||||
| OPS-4 切换与回退 | 停旧系统、启新系统完成切换;出问题回退时停新、启旧,未处理的消息由旧系统继续,数据不丢。 | 切换与回退演练记录。 |
|
| `OPS-4` | 切换与回退:停旧系统、启新系统完成切换;出问题回退时停新、启旧,未处理的消息由旧系统继续,数据不丢。 | 切换与回退演练记录。 |
|
||||||
|
|
||||||
## 4. HTTP 接口清单
|
## 4. HTTP 接口清单
|
||||||
|
|
||||||
|
|||||||
+92
-78
@@ -26,11 +26,13 @@
|
|||||||
| 落信 | 报文进入信箱(`CMINMSGS` 存在该行),执行方是上游。 |
|
| 落信 | 报文进入信箱(`CMINMSGS` 存在该行),执行方是上游。 |
|
||||||
| 入队 | 本系统在自有 PG 建立 `PROC_STATE` 记录,开始处理。 |
|
| 入队 | 本系统在自有 PG 建立 `PROC_STATE` 记录,开始处理。 |
|
||||||
| 已回填 | 本系统已把处理标记写回该信箱行。 |
|
| 已回填 | 本系统已把处理标记写回该信箱行。 |
|
||||||
|
| 处理完成 | 消息的业务数据已在自有 PG 落库、Redis 投影也写成功后的终态;Redis 写失败不算完成(`INV-23`)。 |
|
||||||
| 投递确认 | 投递目标已接受且本地 `MSG_EVENT` 已置 `SENT`;不表示业务消费者已消费。 |
|
| 投递确认 | 投递目标已接受且本地 `MSG_EVENT` 已置 `SENT`;不表示业务消费者已消费。 |
|
||||||
| 自有 PG | 本系统唯一的业务数据库 PostgreSQL;与信箱之间不存在跨库事务。 |
|
| Redis 投影 | 本系统写入的航班查询投影;不是权威,也不是处理状态(`INV-11b`、`INV-24`)。 |
|
||||||
| admin-api | 本网关处理结果的下游只读消费者;从选定的业务数据库读取,不向本网关提供数据。 |
|
| 自有 PG | 本系统唯一的业务数据库 PostgreSQL;与信箱之间不存在跨库事务。生产环境用 PostgreSQL 还是 Oracle 11g 未定,Oracle 适配验证通过前不构成支持承诺。 |
|
||||||
|
| admin-api | 本网关处理结果的下游只读消费者;直接读取本系统写入的静态参考数据表(`C-31`),不向本系统提供数据。 |
|
||||||
|
|
||||||
管道内部术语(`W`、队头、终态、回填意图)定义在 [implementation.md](implementation.md)「术语与持久化记录」。
|
管道内部术语(队头、终态、待标记、回填意图)定义在 [implementation.md](implementation.md)「术语与持久化记录」。
|
||||||
|
|
||||||
条款状态词只有四种:`[待确认 Qn]`(未取得对方书面确认)、`[已确认 YYYY-MM-DD]`(对方书面确认且已回写)、`[我们单方承诺]`(对外承诺,不依赖对方,已生效)、`[我们自证]`(本系统自身的架构或部署事实,无需对方确认)。
|
条款状态词只有四种:`[待确认 Qn]`(未取得对方书面确认)、`[已确认 YYYY-MM-DD]`(对方书面确认且已回写)、`[我们单方承诺]`(对外承诺,不依赖对方,已生效)、`[我们自证]`(本系统自身的架构或部署事实,无需对方确认)。
|
||||||
|
|
||||||
@@ -42,33 +44,34 @@
|
|||||||
|
|
||||||
**ID 与可见性**
|
**ID 与可见性**
|
||||||
|
|
||||||
- **C-1** ID 单调:信箱 ID 按提交顺序分配,已发布水位之下不再出现更小的新 ID。`[待确认 Q2]`
|
- **C-1** ID 单调:信箱 ID 按提交顺序分配,已发布水位之下不再出现更小的新 ID。`[待确认 Q2]` **[作废 by C-30]**
|
||||||
- **C-2** ID 分配 → 事务可见时延上界由库方**直接给出**。该值决定空洞老化阈值;**不可由 SIS 报文 `Expiry` 推导**(`Expiry` 是报文保留与传输恢复口径,与「ID 分配后多久对读事务可见」不是同一个量)。`[待确认 Q2]`
|
- **C-2** ID 分配 → 事务可见时延上界由库方**直接给出**。该值决定空洞老化阈值;**不可由 SIS 报文 `Expiry` 推导**(`Expiry` 是报文保留与传输恢复口径,与「ID 分配后多久对读事务可见」不是同一个量)。`[待确认 Q2]` **[作废 by C-30]**(2026-09-14:扫描改为处理标记谓词,按轮自愈,可见时延不再决定任何阈值。)
|
||||||
- **C-3** ID 空间不复位、不复用、不回退:含表轮换、备份恢复、`AUTO_INCREMENT` 归零。采用整表轮换方案时,新表种子必须 ≥ `max(ID)+1`,保证 ID 不断链;本系统的水位 `W` 是不可逆单游标,ID 回退会导致其后所有行永久不可见。`[待确认 Q2]`
|
- **C-3** ID 空间不复位、不复用、不回退:含表轮换、备份恢复、`AUTO_INCREMENT` 归零。采用整表轮换方案时,新表种子必须 ≥ `max(ID)+1`,保证 ID 不断链;本系统的水位 `W` 是不可逆单游标,ID 回退会导致其后所有行永久不可见。`[待确认 Q2]`
|
||||||
- **C-4** 报文行不可变:同一业务身份(`SNDR|TYPE|STYP|SEQN`)的重发必为同一内容。若上游会以同一身份改发正文,需要另定识别规则(`Q15`)。`[待确认 Q15]`
|
- **C-4** 报文行不可变:同一业务身份(`SNDR|TYPE|STYP|SEQN`)的重发必为同一内容。若上游会以同一身份改发正文,需要另定识别规则(`Q15`)。`[待确认 Q15]`
|
||||||
|
|
||||||
**保留与清除(标记、保留期、清除前提)**
|
**保留与清除(标记、保留期、清除前提)**
|
||||||
|
|
||||||
- **C-5** 处理标记值集与写权限:本系统只写入库方认可的 legacy 值集内的「已处理」值(默认值见 [reference.md](reference.md) `PARAM:mailbox.processed-value`),只写空标记、不回撤、不覆盖;内部原因(死信、重复、放弃)记录在自有 PG,**不在信箱新增枚举**。`[待确认 Q7]`
|
- **C-5** 处理标记值集与写权限:本系统只写入库方认可的 legacy 值集内的「已处理」值(默认值见 [reference.md](reference.md) `PARAM:mailbox.processed-value`),只写空标记、不回撤、不覆盖;内部原因(死信、重复、放弃)记录在自有 PG,**不在信箱新增枚举**。`[待确认 Q7]`
|
||||||
- **C-6** 清除语义必须是「标记 + 保留期」:打标本身不触发清除,触发条件是「到达保留期 `R_keep`」且「边界内全部行已打标」。若库方语义是「打标即可清除」,则清除前置条件不成立,且**增大 `R` 无法补救**,必须另行约定保留期或引入独立原文保留通道。`[待确认 Q7][待确认 Q9]`
|
- **C-6** 清除语义必须是「标记 + 保留期」:打标本身不触发清除,触发条件是「到达保留期 `R_keep`」且「边界内全部行已打标」。若库方语义是「打标即可清除」,则清除前置条件不成立,且**增大 `R` 无法补救**,必须与库方另定保留期。`[待确认 Q7][待确认 Q9]`
|
||||||
- **C-7** 保留期下界(本文件是唯一定义处):
|
- **C-7** 保留期下界(本文件是唯一定义处):
|
||||||
`R_keep ≥ max(人工重放期限 + 人工处置期限, 审计期限, 回填重试上限)`。
|
`R_keep ≥ max(审计期限, 回填重试上限)`。
|
||||||
这是「重放窗口内原文仍在」的**唯一保证来源**。报文在 CIIMS 的 `Expiry`(480 分钟量级,`SIS:3.16`)可作为原文保留期的参照,但它是报文有效期,不等于本处所需的保留期。`[待确认 Q6][待确认 Q9]`
|
报文在 CIIMS 的 `Expiry`(480 分钟量级,`SIS:3.16`)可作为原文保留期的参照,但它是报文有效期,不等于本处所需的保留期。`[待确认 Q7][待确认 Q9]`
|
||||||
- **C-8** 清除前置条件(本文件是唯一定义处):执行清除时,边界内**每行必须已有终局**——即「已持有处理标记」**或**「已登记在本系统的回填放弃清单中且经人工对账确认」。放弃行不写标记,未达终态的行顺延至处理完成后清除;本系统不执行 DDL,也不写共享历史表。`[待确认 Q7][待确认 Q9]`
|
- **C-8** 清除前置条件(本文件是唯一定义处):执行清除时,边界内**每行必须已有终局**——即「已持有处理标记」**或**「已登记在本系统的回填放弃清单中且经人工对账确认」。放弃行不写标记,未达终态的行顺延至处理完成后清除;本系统不执行 DDL,也不写共享历史表。`[待确认 Q7][待确认 Q9]`
|
||||||
- **C-9** 清除执行方与方案:清除由库方执行或书面授权执行。方案 A(按 `DATE_RECEIVED` 日分区 + `TRUNCATE/DROP PARTITION`)为首选;方案 B(`CREATE TABLE ... LIKE` + 保留窗复制 + `RENAME TABLE` + 对账 + `CMINMSGS_HST` 归档 + `DROP`)为备选。现场 MySQL 版本与分区 DDL 能力待确认。`[待确认 Q9]`
|
- **C-9** 清除执行方与方案:清除由库方执行或书面授权执行。方案 A(按 `DATE_RECEIVED` 日分区 + `TRUNCATE/DROP PARTITION`)为首选;方案 B(`CREATE TABLE ... LIKE` + 保留窗复制 + `RENAME TABLE` + 对账 + `CMINMSGS_HST` 归档 + `DROP`)为备选。现场 MySQL 版本与分区 DDL 能力待确认。`[待确认 Q9]`
|
||||||
- **C-10** 时间语义:时间比较与换算统一采用机场时区 `Asia/Shanghai` 及明确类型转换;`DATE_RECEIVED` 由上游/库方写入,其时钟基准需可解释(见 `PRE-4`)。`[待确认 Q7]`
|
- **C-10** 时间语义:时间比较与换算统一采用机场时区 `Asia/Shanghai` 及明确类型转换;`DATE_RECEIVED` 由上游/库方写入,其时钟基准需可解释(见 `PRE-4`)。`[待确认 Q7]`
|
||||||
|
|
||||||
**原文保留与重放**
|
**原文保留**
|
||||||
|
|
||||||
- **C-11** 重放窗口内的原文必须可读:legacy 现役按接收超 1 天归档并删除 `CMINMSGS`;若沿用该窗口,则与 `C-7` 冲突,须以 `C-7` 为准。`[待确认 Q9]`
|
- **C-11** legacy 现役按接收超 1 天归档并删除 `CMINMSGS`;若沿用该窗口,则与 `C-7` 冲突,须以 `C-7` 为准。`[待确认 Q9]`
|
||||||
- **C-12** 若原文被提前清除(违反保留契约),本系统的死信处置不变,按契约违例走运维追责;该情形不改变 `C-8` 的清除前提。`[我们单方承诺]`
|
- **C-12** 若原文被提前清除(违反保留契约),本系统的死信处置不变,按契约违例走运维追责;该情形不改变 `C-8` 的清除前提。`[我们单方承诺]`
|
||||||
|
|
||||||
**我们向库方的承诺**
|
**我们向库方的承诺**
|
||||||
|
|
||||||
- **C-13** 只读约定区间的信箱行(`ID > W`),单活动实例运行,不引入并行消费者。`[我们单方承诺]`
|
- **C-13** 只读约定区间的信箱行(`ID > W`),单活动实例运行,不引入并行消费者。`[我们单方承诺]` **[作废 by C-30]**
|
||||||
- **C-14** 不建表、不改表结构、不迁移 schema、不写共享历史表;兼容 HTTP 入口按既有契约写入入站信箱。`[我们单方承诺]`
|
- **C-14** 不建表、不改表结构、不迁移 schema、不写共享历史表;兼容 HTTP 入口按既有契约写入入站信箱。`[我们单方承诺]`
|
||||||
- **C-15** 处理标记只写 `C-5` 认可的值,不回撤、不覆盖已有非空标记。`[我们单方承诺]`
|
- **C-15** 处理标记只写 `C-5` 认可的值,不回撤、不覆盖已有非空标记。`[我们单方承诺]`
|
||||||
- **C-16** 回填放弃清单在对应信箱边界被清除前必须保持可查:`C-8` 以本清单作为清除授权证据之一,该证据不得随处理记录的归档或清除而消失。`[我们单方承诺][待确认 Q7][待确认 Q9]`
|
- **C-16** 回填放弃清单在对应信箱边界被清除前必须保持可查:`C-8` 以本清单作为清除授权证据之一,该证据不得随处理记录的清除而消失。`[我们单方承诺][待确认 Q7][待确认 Q9]`
|
||||||
|
- **C-30** 信箱读取口径:本系统按配置周期扫描信箱,谓词为「处理标记为空」,按编号升序读取、每批有上限;单活动实例运行,不引入并行消费者。编号即到达顺序:已读过的编号之后不应再出现更小的新编号(较小编号迟提交只会被发现得晚,不会丢;ID 空间不复位、不复用见 `C-3`)。`[我们单方承诺]`(顺序依据 `[待确认 Q2]`)
|
||||||
|
|
||||||
### 2.2 上游(SIS / AODB)
|
### 2.2 上游(SIS / AODB)
|
||||||
|
|
||||||
@@ -76,28 +79,28 @@
|
|||||||
- **C-21** `FLID` 在保留期内不复用。若复用,事件版本(`STATE_VERSION`)必须按 incarnation 作用域,否则「保留最新版本」的合并规则会把新航班的事件压掉,旧 tombstone 也可能删掉在用航班。`[待确认 Q16]`
|
- **C-21** `FLID` 在保留期内不复用。若复用,事件版本(`STATE_VERSION`)必须按 incarnation 作用域,否则「保留最新版本」的合并规则会把新航班的事件压掉,旧 tombstone 也可能删掉在用航班。`[待确认 Q16]`
|
||||||
- **C-22** 报文不可变(同 `C-4`)。`[待确认 Q15]`
|
- **C-22** 报文不可变(同 `C-4`)。`[待确认 Q15]`
|
||||||
- **C-23** 请求/应答回显契约:目标优先按已确认的回显字段精确匹配;回显未确认时的降级匹配(同类开放请求且报文 `DTTM ≥ sentAt`)存在跨代误配风险,必须明确接受并审计,不得宣称精确关联。比较前统一时区与时间单位。`[待确认 Q5]`
|
- **C-23** 请求/应答回显契约:目标优先按已确认的回显字段精确匹配;回显未确认时的降级匹配(同类开放请求且报文 `DTTM ≥ sentAt`)存在跨代误配风险,必须明确接受并审计,不得宣称精确关联。比较前统一时区与时间单位。`[待确认 Q5]`
|
||||||
- **C-24** 出站信箱 `COUTMSGS`:消费方与消费顺序、`COUTMSGS_ACK_DATE_RECV` / `COUTMSGS_ACK_RESEND_TIMES` / `COUTMSGS_DATE_SENT` / `COUTMSGS_ERROR` 各列语义与写入责任、出站行清除责任与保留期、落信成功但本地未置 `SENT` 时的重复写入风险及下游去重契约,均未确认。本系统对出站的交付承诺只到**落信**为止。`[待确认 Q10]`
|
- **C-24** 出站信箱 `COUTMSGS`:消费方为 CIIMS adapter。未确认项:消费顺序、`COUTMSGS_ACK_DATE_RECV` / `COUTMSGS_ACK_RESEND_TIMES` / `COUTMSGS_DATE_SENT` / `COUTMSGS_ERROR` 各列语义与写入责任、出站行清除责任与保留期、落信成功但本地未置 `SENT` 时的重复写入风险及下游去重契约。本系统对出站的交付承诺只到**落信**为止。`[待确认 Q10]`
|
||||||
- **C-25** 主 / 共享删除顺序与 EROR 回报:SIS 要求删主航班前先删子共享航班,顺序不符时 RMS 应向 AODB 回发 EROR(`SIS:1.6.1-1.d`,事件定义 `SIS:4.8`);现行设计为幂等原子级联、不回发 EROR。二选一。`[待确认 Q14]`
|
- **C-25** 删除主航班时级联删除其共享航班,原子提交、不允许删一半;不向 AODB 回发 EROR。`[我们单方承诺]`(2026-09-14 定案,依据 `US-06` AC2;SIS 原要求见 `SIS:1.6.1-1.d`、`SIS:4.8`。)
|
||||||
- **C-26** 日计划缺失可选字段的语义:SIS 要求最新日计划中未发送的可选字段表示 AODB 已无该数据、子系统应删除本地值(`SIS:3.16-note-4`,RESP 同格式见 `SIS:3.17`),与现行「未携带字段保留」相反。`[待确认 Q13]`
|
- **C-26** 日计划快照中未携带的可选字段视为 AODB 已删除该值,本地同步清除。`[我们单方承诺]`(2026-09-14 定案,依据 `US-07` AC3;SIS 语义见 `SIS:3.16-note-4`、`SIS:3.17`。)
|
||||||
- **C-27** 历史积压批次中「不再处理」的确认主体、审批留痕与跳过值集。`[待确认 Q12]`
|
- **C-28** 兼容 HTTP 入口的响应只表示**接收结果**,不表示业务处理成功:成功返回信箱编号,失败不返回编号;目标为现役 `ResponseDto`。请求媒体类型支持 `text/xml`、`application/xml`、`text/plain`,默认 UTF-8;请求体上限取值(暂定 10MB)与失败响应样例仍需与现役逐项对拍。仅限内网使用,来源由网络层限制。`[待确认 Q3]`
|
||||||
|
|
||||||
**我们向上游的承诺**
|
|
||||||
|
|
||||||
- **C-28** 兼容 HTTP 入口的响应只表示**接收结果**,不表示业务处理成功:目标为现役 `ResponseDto`(`is_success` / `body`),请求体上限暂定 10MB;请求媒体类型、字符集与失败响应仍需与现役逐项对拍。`[待确认 Q3]`
|
|
||||||
- **C-29** 对外投递按**至少一次**设计,不承诺端到端恰好一次;Kafka 消息的 key 为 `FLID`,同一 `FLID` 内保序,跨 `FLID` 不承诺顺序。`[待确认 Q4]`
|
- **C-29** 对外投递按**至少一次**设计,不承诺端到端恰好一次;Kafka 消息的 key 为 `FLID`,同一 `FLID` 内保序,跨 `FLID` 不承诺顺序。`[待确认 Q4]`
|
||||||
|
|
||||||
|
### 2.3 下游(admin-api)
|
||||||
|
|
||||||
|
- **C-31** admin-api 直接读取本系统写入的静态参考数据表;本系统不调用 admin-api,也不从 admin-api 拉取、补全或合并任何数据。`[我们单方承诺]`
|
||||||
|
|
||||||
## 3. 前提(外部提供)
|
## 3. 前提(外部提供)
|
||||||
|
|
||||||
前提失效时不变量必须整体重估。
|
前提失效时不变量必须整体重估。
|
||||||
|
|
||||||
| 编号 | 前提 | 若不成立的影响 | 状态 |
|
| 编号 | 前提 | 若不成立的影响 | 状态 |
|
||||||
|---|---|---|---|
|
|---|---|---|---|
|
||||||
| PRE-1 | 信箱消费权排他:同一时刻只有一个系统有权处理、打标、判定可清除(迁移期由切流规程保证单一权威写者) | 水位、身份去重、清除前提全部失效 | `[待确认]`(切流由运维规程保证,上线前另立) |
|
| PRE-1 | 信箱消费权排他:同一时刻只有一个系统有权处理、打标、判定可清除(迁移期由切流规程保证单一权威写者) | 采集谓词、身份去重、清除前提全部失效 | `[待确认]`(切流由运维规程保证,上线前另立) |
|
||||||
| PRE-2 | ID 单调 + 可见时延上界:见 `C-1`/`C-2` | 水位只能当快路径提示;空洞老化阈值无依据;不能声明发现完整性 | `[待确认 Q2]` |
|
| PRE-2 | 信箱 ID 分配顺序即到达顺序:见 `C-30` | 「编号即到达顺序」的顺序声称失去依据 | `[待确认 Q2]` |
|
||||||
| PRE-3 | ID 空间不复位、不复用、不回退:见 `C-3` | 水位(不可逆单游标)之后的行永久不可见 | `[待确认 Q2]` |
|
| PRE-3 | ID 空间不复位、不复用、不回退:见 `C-3` | 处理记录按信箱编号唯一的前提被破坏,同编号可能重复登记 | `[待确认 Q2]` |
|
||||||
| PRE-4 | 报文的 `DATE_RECEIVED` 时钟基准可解释(偏斜在有界范围内) | 跨系统时间比较(`RECEIVED_AT` 与本地 `NOW`)会提前或推迟判定 | `[待确认 Q7]` |
|
| PRE-4 | 报文的 `DATE_RECEIVED` 时钟基准可解释(偏斜在有界范围内) | 跨系统时间比较(`RECEIVED_AT` 与本地 `NOW`)会提前或推迟判定 | `[待确认 Q7]` |
|
||||||
| PRE-5 | 单活动实例运行(信箱读取不加锁、水位是单行覆盖写) | 水位互相覆盖、空洞计时失真 | `[我们自证]`(部署约束,见 architecture.md) |
|
| PRE-5 | 单活动实例运行(信箱读取不加锁) | 并行读会让「已处理」判定互相踩踏 | `[我们自证]`(部署约束,见 architecture.md) |
|
||||||
| PRE-6 | 信箱与自有 PG 之间没有跨库事务 | 回填、水位推进、清除都不能声称原子 | `[我们自证]`(架构事实) |
|
| PRE-6 | 信箱与自有 PG 之间没有跨库事务 | 回填、清除都不能声称原子 | `[我们自证]`(架构事实) |
|
||||||
| PRE-7 | 报文不可变:同一业务身份的重发必为同一内容:见 `C-4` | 上游改发会被判为重复并静默跳过 | `[待确认 Q15]` |
|
| PRE-7 | 报文不可变:同一业务身份的重发必为同一内容:见 `C-4` | 上游改发会被判为重复并静默跳过 | `[待确认 Q15]` |
|
||||||
| PRE-8 | `FLID` 在保留期内不复用:见 `C-21` | 「保留最新版本」的合并规则可能压掉新航班事件,旧 tombstone 可能删掉在用航班 | `[待确认 Q16]` |
|
| PRE-8 | `FLID` 在保留期内不复用:见 `C-21` | 「保留最新版本」的合并规则可能压掉新航班事件,旧 tombstone 可能删掉在用航班 | `[待确认 Q16]` |
|
||||||
|
|
||||||
@@ -106,10 +109,11 @@
|
|||||||
### 4.1 管道
|
### 4.1 管道
|
||||||
|
|
||||||
- **INV-1** 五个独立事实互不替代:落信 / 入队 / 处理完成 / 已回填 / 投递确认各有独立证据,前一个不蕴含后一个。
|
- **INV-1** 五个独立事实互不替代:落信 / 入队 / 处理完成 / 已回填 / 投递确认各有独立证据,前一个不蕴含后一个。
|
||||||
- **INV-2** 水位与入队同事务:不允许出现「水位已推进、消息未入队」的持久化状态;水位只增不减,遇空洞即停,只有判定为永久空洞才放行,且放行只跳过空洞本身、不越过任何已存在的行。
|
- **INV-2** 水位与入队同事务:不允许出现「水位已推进、消息未入队」的持久化状态;水位只增不减,遇空洞即停,只有判定为永久空洞才放行,且放行只跳过空洞本身、不越过任何已存在的行。**[作废 by INV-2b]**
|
||||||
|
- **INV-2b** 扫描谓词与幂等登记:每轮按编号升序读取「处理标记为空」的信箱行,每批有上限;同一编号只登记一次(`INV-9`);重复扫描与重启恢复不重复登记、不重复处理、不丢行;终态但未回填的行会被重复读到,按已有记录幂等跳过。
|
||||||
- **INV-3** 队头唯一:任一时刻只有一个可执行队头(最小未完成 `MSG_ID`,`PENDING` 与 `FAILED` 都占位);`FAILED` 未退避到期时后续消息不得越过。
|
- **INV-3** 队头唯一:任一时刻只有一个可执行队头(最小未完成 `MSG_ID`,`PENDING` 与 `FAILED` 都占位);`FAILED` 未退避到期时后续消息不得越过。
|
||||||
- **INV-4** 只领取已发现的行:主泵只领 `MSG_ID ≤ W`;水位之外的行只可能来自兼容入口,必须等水位追平后按序处理。
|
- **INV-4** 只领取已发现的行:主泵只领 `MSG_ID ≤ W`;水位之外的行只可能来自兼容入口,必须等水位追平后按序处理。**[作废 by INV-2b]**(水位取消,兼容入口写入的行即普通行。)
|
||||||
- **INV-5** 发现与处理互不阻塞:收报只看 `ID > W`,不以处理标记为谓词;终态而未回填的行不阻断后续消息的发现。
|
- **INV-5** 发现与处理互不阻塞:收报只看 `ID > W`,不以处理标记为谓词;终态而未回填的行不阻断后续消息的发现。**[作废 by INV-2b]**
|
||||||
- **INV-6** 处理终态不可逆:已提交的 `SUCCEEDED` 不因回填或投递失败回改。
|
- **INV-6** 处理终态不可逆:已提交的 `SUCCEEDED` 不因回填或投递失败回改。
|
||||||
- **INV-7** 处理标记单调:任何路径只把空标记写成已处理值,不回撤、不覆盖。
|
- **INV-7** 处理标记单调:任何路径只把空标记写成已处理值,不回撤、不覆盖。
|
||||||
- **INV-8** 回填只针对终态(`PENDING` / `FAILED` 永不写标记);「还欠一次回填」的事实与终态由**同一条语句**落库,不存在第二处落账。
|
- **INV-8** 回填只针对终态(`PENDING` / `FAILED` 永不写标记);「还欠一次回填」的事实与终态由**同一条语句**落库,不存在第二处落账。
|
||||||
@@ -118,30 +122,40 @@
|
|||||||
|
|
||||||
### 4.2 航班域
|
### 4.2 航班域
|
||||||
|
|
||||||
- **INV-11** 自有 PG 的航班当前态是唯一权威;信箱、Kafka、展示视图都不是权威。
|
- **INV-11** 自有 PG 的航班当前态是唯一权威;信箱、Kafka、展示视图都不是权威。**[作废 by INV-11b]**
|
||||||
|
- **INV-11b** 自有 PG 的航班当前态是唯一权威;信箱、Redis 投影、Kafka、展示视图都不是权威。
|
||||||
- **INV-12** `FLID` 唯一;已写入非空的 `OPERATION_DAY` 不可改变。
|
- **INV-12** `FLID` 唯一;已写入非空的 `OPERATION_DAY` 不可改变。
|
||||||
- **INV-13** 每个航班每次成功状态写入单调推进 `STATE_VERSION`;重复消息不重复推进。
|
- **INV-13** 每个航班每次成功状态写入单调推进 `STATE_VERSION`;重复消息不重复推进。
|
||||||
- **INV-14** 报文未携带的字段不被隐式清空;集合按完整合并结果写入,保留输入顺序与源序号。
|
- **INV-14** 报文未携带的字段不被隐式清空;集合按完整合并结果写入,保留输入顺序与源序号。**[作废 by INV-14b]**
|
||||||
- **INV-15** 缺席于某个日计划不构成删除理由;删除只由 FDEL 或受控历史清理触发。
|
- **INV-14b** 增量报文(FLOP/ADFT)未携带的字段不被隐式清空;集合按完整合并结果写入,保留输入顺序与源序号。日计划快照不适用本条(`INV-15b`)。
|
||||||
|
- **INV-15** 缺席于某个日计划不构成删除理由;删除只由 FDEL 或受控历史清理触发。**[作废 by INV-15b]**
|
||||||
|
- **INV-15b** 日计划快照以 AODB 下发为准:快照里没有的航班删除——标记已删除、登记删除事件、从 Redis 投影移除;快照里未携带的字段视为 AODB 已删除该值,本地同步清除(`US-07` AC2/AC3)。
|
||||||
- **INV-16** 外部副作用(回填、Kafka 投递、出站信箱)失败可重试,但不回滚已提交的本地业务结果。
|
- **INV-16** 外部副作用(回填、Kafka 投递、出站信箱)失败可重试,但不回滚已提交的本地业务结果。
|
||||||
- **INV-17** 状态变更、待发事件、处理终态与回填意图在同一 PG 事务内原子提交。
|
- **INV-17** 状态变更、待发事件、处理终态与回填意图在同一 PG 事务内原子提交。**[作废 by INV-17b]**
|
||||||
|
- **INV-17b** 状态变更与待发事件在同一 PG 事务内提交;处理终态与回填意图在同一 PG 事务内提交,且该事务在 Redis 投影写成功之后(`INV-23`)。日计划例外:分批写入,每批一个事务(状态变更 + 待发事件),终态与回填意图在整包完成后同一事务提交;失败不标记已处理,下轮整包重新处理(`US-07` AC4)。
|
||||||
- **INV-18** 航班表的写者集合是「主泵处理器」与「历史清理」;两者必须互斥(同一 `PIPELINE_LOCK`,或清理在同一事务内复查判据后再删除),不得出现清理删除与处理器更新同一 `FLID` 的竞态。
|
- **INV-18** 航班表的写者集合是「主泵处理器」与「历史清理」;两者必须互斥(同一 `PIPELINE_LOCK`,或清理在同一事务内复查判据后再删除),不得出现清理删除与处理器更新同一 `FLID` 的竞态。
|
||||||
- **INV-19** 整包校验失败或运营日冲突时整包不落地,既有状态与版本保持不变。
|
- **INV-19** 整包校验失败或运营日冲突时整包不落地,既有状态与版本保持不变。
|
||||||
- **INV-20** 处理器幂等:同一消息重复执行只产生一次业务效果。身份唯一只防「重复记录」,不防「重新执行」;SIS 25 类与经 `Q8` 定案启用的 legacy 子类型完成逐类幂等矩阵前,本条**不可声明**(`G-FLOP-IDEMPOTENT`)。
|
- **INV-20** 处理器幂等:同一消息重复执行只产生一次业务效果。身份唯一只防「重复记录」,不防「重新执行」;SIS 25 类与经 `Q8` 定案启用的 legacy 子类型完成逐类幂等矩阵前,本条**不可声明**(`G-FLOP-IDEMPOTENT`)。**[作废 by INV-20b]**
|
||||||
|
- **INV-20b** 处理器幂等:同一消息重复执行(失败重处理、重复发现)只产生一次业务效果。身份唯一只防「重复记录」,不防「重新执行」;逐类幂等矩阵(SIS 25 类与现场延续的 7 类)补全前,本条**不可声明**(`G-FLOP-IDEMPOTENT`)。
|
||||||
- **INV-21** `MAFL` 是派生投影:内容恒等于「`STATE = ACTIVE` 且 `MAID = 主航班 FLID`」的子航班集合(元素 `FLID` + `FLNO`,按 `FLID` 升序),不落库、不从入站解析;自引用与悬挂引用不入投影。
|
- **INV-21** `MAFL` 是派生投影:内容恒等于「`STATE = ACTIVE` 且 `MAID = 主航班 FLID`」的子航班集合(元素 `FLID` + `FLNO`,按 `FLID` 升序),不落库、不从入站解析;自引用与悬挂引用不入投影。
|
||||||
- **INV-22** 子航班集合变化必须使涉及的主航班在同一事务内推进 `STATE_VERSION` 并登记主航班事件;投影只进不退,版本不推进即被下游丢弃。
|
- **INV-22** 子航班集合变化必须使涉及的主航班在同一事务内推进 `STATE_VERSION` 并登记主航班事件;投影只进不退,版本不推进即被下游丢弃。
|
||||||
|
- **INV-23** Redis 投影写成功才算处理完成:写失败的消息不置终态、不写回填标记,保持未完成,下轮重新处理;自有 PG 已提交的业务结果不因此回滚(`US-05` AC4、`US-06` AC1)。
|
||||||
|
- **INV-24** Redis 航班投影只由本系统写入与移除;`GET /all/flights` 与网页客户端同源读 Redis;Redis 异常时报错,不返回空列表伪装成功(`US-12` AC1/AC2)。
|
||||||
|
- **INV-25** 处理记录清理:只删「终态且已回填」且超过保留期的记录;未完成的不删。保留期可配置(`US-11`)。
|
||||||
|
- **INV-26** 静态参考数据按(类别, 编号)保存,新消息覆盖旧记录;全量消息整体替换,增删改消息逐条处理;消息里字段为空表示「当前没有值」,不是删除(`US-13` AC1/AC3/AC4)。
|
||||||
|
- **INV-27** 一类参考数据校验不通过就不更新这一类,其他类照常处理;该类已有数据不动(`US-13` AC2)。
|
||||||
|
- **INV-28** 航班先写历史存储、确认成功后才从实时数据删除;写入失败下次重来,已写入的不重复写入;单个航班失败不影响其他航班;正在被消息处理的航班跳过、下轮再处理(`US-14` AC3/AC4;写者互斥见 `INV-18`)。
|
||||||
|
|
||||||
## 5. 声明边界
|
## 5. 声明边界
|
||||||
|
|
||||||
| 编号 | 主张 | 依赖 | 当前可否声明 | 挂起原因 |
|
| 编号 | 主张 | 依赖 | 当前可否声明 | 挂起原因 |
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
| CLM-3 | 重放不产生重复业务副作用 | INV-20、`G-FLOP-IDEMPOTENT` | **不可** | 启用的 FLOP 子类型幂等矩阵未补全;重放不恢复历史顺序 |
|
| CLM-3 | 失败重处理与重复发现不产生重复业务副作用 | INV-20b、`G-FLOP-IDEMPOTENT` | **不可** | 逐类幂等矩阵未补全 |
|
||||||
| CLM-4 | 回填不会被短暂故障放弃:最终打标,或进入可对账的放弃清单 | INV-8、`C-5`、`C-8` | **可声明(有条件)** | 条件:`R` 之前不放弃;`MISSING_ROW` 立即放弃并告警;放弃行须经人工对账才可用于清除判定(`C-8`)。原文保留另见 CLM-5 |
|
| CLM-4 | 回填不会被短暂故障放弃:最终打标,或进入可对账的放弃清单 | INV-8、`C-5`、`C-8` | **可声明(有条件)** | 条件:`R` 之前不放弃;`MISSING_ROW` 立即放弃并告警;放弃行须经人工对账才可用于清除判定(`C-8`) |
|
||||||
| CLM-5 | 重放窗口内原文仍可读 | `C-6`、`C-7`、`Q7`、`Q9` | **不可** | 清除语义与保留期未确认;「打标即清除」下无补救 |
|
|
||||||
| CLM-6 | 单实例内严格 FIFO | PRE-5、INV-3 | **可**(限于单活动实例) | — |
|
| CLM-6 | 单实例内严格 FIFO | PRE-5、INV-3 | **可**(限于单活动实例) | — |
|
||||||
| CLM-7 | 事件投递在同一 `FLID` 内保序 | INV-10、投递设计 | **可**(跨 `FLID` 不承诺) | 实现当前按目标级全序投递,收敛到按 `FLID` 属投递改造 |
|
| CLM-7 | 事件投递在同一 `FLID` 内保序 | INV-10、投递设计 | **可**(跨 `FLID` 不承诺) | 实现当前按目标级全序投递,收敛到按 `FLID` 属投递改造 |
|
||||||
| CLM-8 | 出站交付承诺只到「落信」 | `C-24`、`Q10` | **可**(仅落信语义) | 消费方与 ACK 列语义未确认 |
|
| CLM-8 | 出站交付承诺只到「落信」 | `C-24`、`Q10` | **可**(仅落信语义) | 消费方已定(CIIMS adapter);ACK 列语义未确认 |
|
||||||
| CLM-9 | 处理标记延迟由调度周期决定 | — | **不可** | 扫描周期不等于完成时限;批次积压、单行超时与历史作业都会延长实际延迟 |
|
| CLM-9 | 处理标记延迟由调度周期决定 | — | **不可** | 扫描周期不等于完成时限;批次积压、单行超时与清理作业都会延长实际延迟 |
|
||||||
| CLM-10 | 容量量级假设(单实例、入站日消息量千级到万级、单报文 ≤ 10⁴ 字节) | — | **不可** | 未实测,无生产负载数据;解除条件:取得现役信箱日量、峰值与单报文上限后重估 |
|
| CLM-10 | 容量量级假设(单实例、入站日消息量千级到万级、单报文 ≤ 10⁴ 字节) | — | **不可** | 未实测,无生产负载数据;解除条件:取得现役信箱日量、峰值与单报文上限后重估 |
|
||||||
|
|
||||||
## 6. 验证映射
|
## 6. 验证映射
|
||||||
@@ -151,37 +165,39 @@
|
|||||||
| 不变量 / 声明边界 | 场景 | 证据 / 测试 |
|
| 不变量 / 声明边界 | 场景 | 证据 / 测试 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| INV-1 | 五事实互不替代:入队不引用标记、回填不引用投递、投递不引用回填 | 需接口级断言 |
|
| INV-1 | 五事实互不替代:入队不引用标记、回填不引用投递、投递不引用回填 | 需接口级断言 |
|
||||||
| INV-2 | 重复扫描、入队中断 | 不重复入队、不丢记录;`InboxPollerTest` |
|
| INV-2b | 谓词扫描与批次上限 | 只读「处理标记为空」的行、每批有上限;`InboxPollerTest`(随 `G-SCAN-PREDICATE` 改造重写) |
|
||||||
| INV-2 | 空洞老化与重置 | 阈值内不推进、不越过入队;超期只放行空洞本身;旧空洞补齐后新空洞获得完整窗口 |
|
| INV-2b | 重复扫描、重启恢复 | 不重复登记、不重复处理、不丢记录 |
|
||||||
| INV-2 | 水位写入与入队同事务 | 需真实 PG 事务用例 |
|
| INV-3 | 较小 ID 迟提交 | 迟发现的较小编号仍按编号序登记处理,不丢、不重复 |
|
||||||
| INV-3 | 较小 ID 迟提交 | `InboxPollerTest` 钉住「水位越过后到达的较小 ID 不被发现」;水位遇空洞即停、空洞老化放行只跳过空洞本身 |
|
|
||||||
| INV-3 | 队头失败、退避及作业竞争 | 消息不越队;到期后恢复;作业不使消息无限饥饿 |
|
| INV-3 | 队头失败、退避及作业竞争 | 消息不越队;到期后恢复;作业不使消息无限饥饿 |
|
||||||
| INV-4 | 兼容入口与空洞并发 | `PipelineSmokeTest`「compat injected high id is not claimed until the watermark catches up」 |
|
|
||||||
| INV-5 | 终态未回填不阻断发现 | 需断言发现谓词不引用处理状态 |
|
|
||||||
| INV-6 | 投递失败后终态不变 | 需用例 |
|
| INV-6 | 投递失败后终态不变 | 需用例 |
|
||||||
| INV-7 | 回填四种结果 | 写入成功 / 早已标记(不覆盖、记成功)/ 信箱行不存在(立即放弃并告警,不得视为已标记)/ 暂时故障持续到 `R` 仍未打标(停止自动重试,可人工恢复) |
|
| INV-7 | 回填四种结果 | 写入成功 / 早已标记(不覆盖、记成功)/ 信箱行不存在(立即放弃并告警,不得视为已标记)/ 暂时故障持续到 `R` 仍未打标(停止自动重试,可人工恢复) |
|
||||||
| INV-7 | `RECEIVED_AT` 为 NULL | 超期分支仍成立且不导致标记提前写入——判据是本地 `ENQUEUED_AT`,与库方时钟及 NULL 无关 |
|
| INV-7 | `RECEIVED_AT` 为 NULL | 超期分支仍成立且不导致标记提前写入——判据是本地 `ENQUEUED_AT`,与库方时钟及 NULL 无关 |
|
||||||
| INV-8 | PG 提交失败、信箱回填失败 | 事件、终态与回填意图一起回滚;已提交结果只补写标记,不重放业务;中间态永不补写 |
|
| INV-8 | PG 提交失败、回填失败 | 事件、终态与回填意图一起回滚;已提交结果只补写标记,不重放业务;中间态永不补写 |
|
||||||
| INV-8 | 非业务型终态 | 不触碰航班表 / `MSG_EVENT`,只写 `PROC_STATE`,且终态与回填意图同语句生效 |
|
| INV-8 | 非业务型终态 | 不触碰航班表 / `MSG_EVENT`,只写 `PROC_STATE`,且终态与回填意图同语句生效 |
|
||||||
| INV-9 | 同身份多条记录、失败后重试、归档后重复 | 只产生一次有效业务处理,不把自身重试判为重复 |
|
| INV-9 | 同身份多条记录、失败后重试、清理后重复 | 只产生一次有效业务处理,不把自身重试判为重复 |
|
||||||
| INV-10 | 投递确认丢失、批次失败、次数耗尽 | 允许可识别的重发、保持目标顺序、整批退避并保留死信 |
|
| INV-10 | 投递确认丢失、批次失败、次数耗尽 | 允许可识别的重发、保持目标顺序、整批退避并保留死信 |
|
||||||
| INV-11 | 权威唯一 | 需断言展示视图与缓存不得成为写入或对账来源 |
|
| INV-11b | 权威唯一 | 需断言信箱、Redis 投影、展示视图不成为写入或对账来源 |
|
||||||
| INV-12 / INV-13 | PG 事务失败、快照重复或迟到 | 整体回滚重试、不重复推进版本、不回退状态、不误删增量航班 |
|
| INV-12 / INV-13 | PG 事务失败、快照重复或迟到 | 整体回滚重试、不重复推进版本、不回退状态、不误删增量航班 |
|
||||||
| INV-12 | 运营日冲突 | 整包 `DEAD(PROTOCOL)`,既有状态与版本不变 |
|
| INV-12 | 运营日冲突 | 整包 `DEAD(PROTOCOL)`,既有状态与版本不变 |
|
||||||
| INV-14 | 未携带字段保留、显式清空才清除;集合按完整合并结果写入 | `FlightStateEngineTest`「day plan merges scalars overwriting overlaps retaining absent and clearing on explicit empty」「flop merge retains absent scalars and collections」;`FdelAndAdftProcessorTest`「ADFT merge does not clear absent scalars」 |
|
| INV-14b | 增量未携带字段保留、显式清空才清除;集合按完整合并结果写入 | `FlightStateEngineTest`「flop merge retains absent scalars and collections」;`FdelAndAdftProcessorTest`「ADFT merge does not clear absent scalars」 |
|
||||||
| INV-14 | FLOP 逐类空标签语义(清除、撤销、集合清空)与「未携带不清空」的区分 | 逐类用例见 [implementation.md](implementation.md)「动态运行事件」;`G-FLOP-DIRECTION`、`G-FLOP-UNMAPPED`、`G-FLOP-SEMANTICS` |
|
| INV-14b | FLOP 逐类空标签语义(清除、撤销、集合清空)与「未携带不清空」的区分 | 逐类用例见 [implementation.md](implementation.md)「动态运行事件」;`G-FLOP-UNMAPPED`、`G-FLOP-SEMANTICS` |
|
||||||
| INV-15 | 缺席不删除 | 需分别断言 FDEL 与清理路径 |
|
| INV-15b | 快照缺席航班删除、未携带字段清除;增量不适用快照语义 | 新增用例(`G-SCHD-SNAPSHOT`) |
|
||||||
| INV-16 | 外部副作用失败后本地结果不变 | 需用例 |
|
| INV-16 | 外部副作用失败后本地结果不变 | 需用例 |
|
||||||
| INV-17 | 业务型终态四件套同事务 | 需真实 PG 用例 |
|
| INV-17b | 状态与事件同事务;终态与回填意图同事务且晚于 Redis 写成功;日计划分批 | 需真实 PG 用例 |
|
||||||
| INV-18 | 清理与处理并发 | `HistorySweepJobTest`(归档后被主泵更新的航班不删除、不发 tombstone)+ `HistorySweepPurgePgTest`(删除阶段失败时 tombstone 与删除整体回滚) |
|
| INV-18 | 清理与处理并发 | `HistorySweepJobTest`(归档后被主泵更新的航班不删除、不发 tombstone)+ `HistorySweepPurgePgTest`(删除阶段失败时 tombstone 与删除整体回滚) |
|
||||||
| INV-19 | 整包协议拒绝(声明数不符、运营日冲突) | `DEAD(PROTOCOL)`,整包不落地、整体回滚、既有状态不变 |
|
| INV-19 | 整包协议拒绝(声明数不符、运营日冲突) | `DEAD(PROTOCOL)`,整包不落地、整体回滚、既有状态不变 |
|
||||||
| INV-21 | `MAFL` 投影与 `ACTIVE` 子航班集合一致(子航班删除后退出、自引用与悬挂引用不入、顺序确定) | `G-MAFL`:投影未实现 |
|
| INV-21 | `MAFL` 投影与 `ACTIVE` 子航班集合一致(子航班删除后退出、自引用与悬挂引用不入、顺序确定) | `G-MAFL`:投影未实现 |
|
||||||
| INV-22 | 子航班新增、删除、`MAID` 迁移时主航班版本与事件 | `G-MAFL`:主/共享级联未实现 |
|
| INV-22 | 子航班新增、删除、`MAID` 迁移时主航班版本与事件 | `G-MAFL`:主/共享级联未实现 |
|
||||||
| INV-20 / CLM-3 | 重放同一条消息 | 阻塞于启用的 FLOP 子类型逐类幂等矩阵 |
|
| INV-20b / CLM-3 | 同一消息失败重处理、重复发现 | 阻塞于逐类幂等矩阵(`G-FLOP-IDEMPOTENT`) |
|
||||||
|
| INV-23 | Redis 写失败 | 消息保持未完成、不提前写标记;重处理收敛 |
|
||||||
|
| INV-24 | 同源读取与异常 | Redis 异常时报错、不返回空列表 |
|
||||||
|
| INV-25 | 清理谓词 | 只删「终态且已回填」超保留期的记录 |
|
||||||
|
| INV-26 / INV-27 | 参考数据覆盖 / 全量替换 / 空标签 / 逐类门控 | 需用例(`G-REF-DATA`) |
|
||||||
|
| INV-28 | 历史先行 | 历史未确认成功删除 0 条;已写入不重复写入 |
|
||||||
| — | 请求超时、无匹配 RESP、时间单位不一致 | 不误用迟到应答、不提前完成请求 |
|
| — | 请求超时、无匹配 RESP、时间单位不一致 | 不误用迟到应答、不提前完成请求 |
|
||||||
| — | stub 误配置、重复实例、停机中断 | 生产拒绝不安全启动,工作线程能正确退出 |
|
| — | stub 误配置、重复实例、停机中断 | 生产拒绝不安全启动,工作线程能正确退出 |
|
||||||
|
|
||||||
上表首列是**引用**(`INV-x` 的定义见本文件「不变量」);同一行可覆盖多个 `INV`,例如 `INV-20 / CLM-3`。
|
上表首列是**引用**(`INV-x` 的定义见本文件「不变量」);同一行可覆盖多个 `INV`,例如 `INV-20b / CLM-3`。
|
||||||
|
|
||||||
声明边界的证据指针:`CLM-4` 断言放弃行不写标记、不被当作已打标;`CLM-9` 由作业心跳与回填年龄指标提供观测(指标名见 [reference.md](reference.md)「指标与健康」),实际延迟仍需现场数据。
|
声明边界的证据指针:`CLM-4` 断言放弃行不写标记、不被当作已打标;`CLM-9` 由作业心跳与回填年龄指标提供观测(指标名见 [reference.md](reference.md)「指标与健康」),实际延迟仍需现场数据。
|
||||||
|
|
||||||
@@ -192,40 +208,38 @@
|
|||||||
| 偏差 | 含义 | 影响 |
|
| 偏差 | 含义 | 影响 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `G-RESP-GUARD` | `RESP` 应答守卫未实现,当前与 `DNLD` 无差别进入快照写入 | 请求匹配闭环;`C-23` |
|
| `G-RESP-GUARD` | `RESP` 应答守卫未实现,当前与 `DNLD` 无差别进入快照写入 | 请求匹配闭环;`C-23` |
|
||||||
| `G-REQ-TRACK` | `REQ_TRACK` 无运行时协调器:出站适配、请求编码、超时与应答匹配未实现 | `US-08`;`C-24` |
|
| `G-REQ-TRACK` | `REQ_TRACK` 无运行时协调器:出站适配、请求编码、超时与应答匹配未实现 | `US-09`;`C-24` |
|
||||||
| `G-PROC-HST` | `PROC_STATE_HST` 未建表,终态归档未落地 | `US-11`;归档能力 |
|
| `G-FLOP-IDEMPOTENT` | SIS 25 类与现场延续的 7 类(靠桥、延误、计划机位等)尚无完整逐类幂等矩阵 | `INV-20b`、`CLM-3` |
|
||||||
| `G-FLOP-IDEMPOTENT` | SIS 25 类与经 `Q8` 定案启用的 legacy 子类型尚无完整逐类幂等矩阵 | `INV-20`、`CLM-3` |
|
|
||||||
| `G-REPLAY-CHANNEL` | 「打标即清除」语义下的独立原文保留通道未设计 | `CLM-5` |
|
|
||||||
| `G-MAFL` | 主航班 `MAFL` 派生投影及主/共享原子级联未实现(规则见 `INV-21`/`INV-22`);`MAFL` 不是 SIS/XML 入站字段 | 航班完整态;删除与重建 |
|
| `G-MAFL` | 主航班 `MAFL` 派生投影及主/共享原子级联未实现(规则见 `INV-21`/`INV-22`);`MAFL` 不是 SIS/XML 入站字段 | 航班完整态;删除与重建 |
|
||||||
| `G-SRVT-VIPF` | SIS/XML 的 `SRVT`、`VIPF` 无界集合尚未映射到持久化明细;wire/domain 只保留出现事实与原始内容,不参与合并与投递(清空语义见 `Q13`) | 航班完整态;无损字段保存 |
|
| `G-SRVT-VIPF` | SIS/XML 的 `SRVT`、`VIPF` 无界集合尚未映射到持久化明细;wire/domain 只保留出现事实与原始内容,不参与合并与投递(清空语义见 `Q13`) | 航班完整态;无损字段保存 |
|
||||||
| `G-COMPAT-HTTP` | compat 入口仍未实现 `Q3` 定案后的 ResponseDto、媒体类型、字符集、失败响应与请求体上限 | `C-28`;`US-02` |
|
| `G-COMPAT-HTTP` | compat 入口尚未按 `US-02` 口径实现:请求体上限取值与失败响应样例未对拍(媒体类型集与成功/失败响应语义已定案) | `C-28`;`US-02` |
|
||||||
| `G-REQ-OPEN-UNIQUE` | `REQ_TRACK` 尚无约束开放态 `(REQ_TYPE, OPERATION_DAY, SENDER)` 唯一性的部分索引 | `US-08`;`G-REQ-TRACK` |
|
| `G-REQ-OPEN-UNIQUE` | `REQ_TRACK` 尚无约束开放态 `(REQ_TYPE, OPERATION_DAY, SENDER)` 唯一性的部分索引 | `US-09`;`G-REQ-TRACK` |
|
||||||
| `G-HST-RETENTION` | 归档目标(`PROC_STATE_HST` 及后续归档表)的保留期与清除作业未定义 | 归档只转移不减少容量占用;`G-PROC-HST` |
|
| `G-REQ-TRACK-RETENTION` | `REQ_TRACK` 关闭态行(`DONE`/`EXPIRED`)的保留期与清除作业未定义 | 自有 PG 无界增长;`US-09` |
|
||||||
| `G-FLIGHT-HIST-RETENTION` | 航班历史存储(外部)的保留期与容量上限未定义 | `D1`;`FLIGHT_SCHD` 物理清除后历史存储是唯一副本 |
|
| `G-FLIGHT-HIST-RETENTION` | 航班历史存储(外部)的保留期与容量上限未定义 | `INV-28`;实时数据物理清除后历史存储是唯一副本 |
|
||||||
| `G-REQ-TRACK-RETENTION` | `REQ_TRACK` 关闭态行(`DONE`/`EXPIRED`)的保留期与清除作业未定义 | 自有 PG 无界增长;`US-08` |
|
|
||||||
| `G-FLOP-DIRECTION` | 柜台、转盘、滑槽、登机门、计划机位五类的 FLOP 报文按 AODB→RMS 接收并落库,SIS 要求收到即拒绝(这些资源在 AODB 方向只随日计划下发) | `US-05`;`SIS:3.24`、`SIS:3.25`、`SIS:3.26`、`SIS:3.34`、`SIS:3.38` |
|
|
||||||
| `G-FLOP-UNMAPPED` | [XSD](legacy/unisysaodbsis.xsd)「FLOP 元素」的 `FFID`、`UNCL`、`CKOP`、`GTOP`、`CKCL`、`BDOP`、`LCTM`、`BDCL`、`FRET`、`FDIV`、`FLAB`、`RUNW`、`PXNO`、`FLBG`、`CKPB`、`BDPB` 未解码;`CHDT.CCLS/CTYP` 被错误写成 `CHCLS/CHTYP`,均会静默丢失。其中 `FRET`、`FDIV`、`BDPB` 在 legacy 有对应处理 | `US-05`;无损字段保存 |
|
| `G-FLOP-UNMAPPED` | [XSD](legacy/unisysaodbsis.xsd)「FLOP 元素」的 `FFID`、`UNCL`、`CKOP`、`GTOP`、`CKCL`、`BDOP`、`LCTM`、`BDCL`、`FRET`、`FDIV`、`FLAB`、`RUNW`、`PXNO`、`FLBG`、`CKPB`、`BDPB` 未解码;`CHDT.CCLS/CTYP` 被错误写成 `CHCLS/CHTYP`,均会静默丢失。其中 `FRET`、`FDIV`、`BDPB` 在 legacy 有对应处理 | `US-05`;无损字段保存 |
|
||||||
| `G-FLOP-SEMANTICS` | FLOP 未按 SIS 25 类建立 `STYP` 白名单;`ROUT` 未按方向截取 4 条且仍保存 `SCAT`/`SCDT`;BOTM/LACL 未同步设置或重置运行状态;除 FDEL 外,已删除航班仍会被合并、增版并发事件 | `US-05`、`INV-14`、`INV-20`;`Q8` |
|
| `G-FLOP-SEMANTICS` | FLOP 未按 SIS 25 类建立 `STYP` 白名单;`ROUT` 未按方向截取至 4 条且仍保存 `SCAT`/`SCDT`;BOTM/LACL 未同步设置或重置运行状态;除 FDEL 外,已删除航班仍会被合并、增版并发事件 | `US-05`、`INV-14b`、`INV-20b` |
|
||||||
| `G-REF-DATA` | SIS 静态参考数据消息处理(`SIS:3.1`~`SIS:3.14`)未实现;当前忽略规则还会直接跳过 `REGN`/`RSTA`,`REF_MASTER` 及 admin-api 下游读取契约均只有逻辑目标定义 | `US-04`、`US-13`、`US-14` |
|
| `G-REF-DATA` | SIS 静态参考数据处理(`SIS:3.1`~`SIS:3.14`)未实现;当前按「合法但不支持」跳过并回填(`US-03` AC2),独立参考数据表与 admin-api 直读未落地 | `US-13`、`US-03` |
|
||||||
|
| `G-SCAN-PREDICATE` | 收报仍按持久水位 ID 区间扫描(含空洞老化与切流播种),未达「处理标记为空」谓词口径 | `US-01`;`INV-2b` |
|
||||||
|
| `G-REDIS-PROJECTION` | 无任何 Redis 投影写/移除路径:航班动态写入、删除移除、快照刷新、查询读取均未实现 | `US-05`、`US-06`、`US-07`、`US-12` |
|
||||||
|
| `G-SCHD-SNAPSHOT` | 日计划快照未达 `US-07` 口径:缺席航班不删除、未携带字段不清除、整包单事务(需求要求分批、每批一个事务) | `INV-15b`、`INV-17b` |
|
||||||
|
| `G-PROC-CLEANUP` | 处理记录到期清理作业未实现(归档链随 `US-11` 口径废弃) | `US-11`;`INV-25` |
|
||||||
|
|
||||||
## 8. 待确认事项台账
|
## 8. 待确认事项台账
|
||||||
|
|
||||||
| 编号 | 事项 | 当前假定 | 阻塞 | 状态 |
|
| 编号 | 事项 | 当前假定 | 阻塞 | 状态 |
|
||||||
|---|---|---|---|---|
|
|---|---|---|---|---|
|
||||||
| Q1 | 权威存储(内部方向) | 自有 PG 单库权威 + 无损明细;现场供库目标 Oracle 11g | — | 已定案(内部),Oracle 适配与部署验收另计 |
|
| Q1 | 权威存储(内部方向)与生产库选型 | 自有 PG 单库权威 + 无损明细;生产环境用 PostgreSQL 还是 Oracle 11g 未定,Oracle 适配验证通过前不构成支持承诺 | 生产部署验收 | 已定案(内部),生产库待定 |
|
||||||
| Q2 | 信箱 ID 单调、ID 分配→事务可见时延上界、ID 空间不复位;空洞与迟到处置 | 时延按 5 分钟 `max-commit-delay`(**缺少依据的占位值**,不可由 SIS `Expiry` 推导) | 发现完整性声明、空洞老化阈值、水位不可逆性 | 未确认 |
|
| Q2 | 信箱 ID 分配顺序即到达顺序;ID 空间不复位、不复用 | — | 到达顺序声称(`US-01` AC3) | 未确认 |
|
||||||
| Q3 | HTTP 契约:媒体类型、字符集、错误码、查询接口对拍 | 目标与上限见 `C-28` | 兼容入口验收 | 未确认 |
|
| Q3 | HTTP 契约:请求体上限取值、失败响应样例 | 上限暂定 10MB(`C-28`) | 兼容入口验收 | 未确认 |
|
||||||
| Q4 | Kafka wire:发送粒度、key、去重标识、分区与批次确认 | 逐 `FLID` 发送,key=`FLID` | 投递契约 | 未确认 |
|
| Q4 | Kafka 载荷与去重标识 | 主题/粒度/保序已按 `US-08` 定案:`msg` 发单条变更、`schd` 定时批量发最新状态、key=`FLID` | 投递契约 | 未确认 |
|
||||||
| Q5 | 请求匹配:回显字段可靠性与降级匹配 | `RQFD` 60 秒 / `RQRD` 30 秒超时 | 请求跟踪闭环 | 未确认 |
|
| Q5 | 请求匹配:回显字段可靠性与降级匹配 | `RQFD` 60 秒 / `RQRD` 30 秒超时 | 请求跟踪闭环 | 未确认 |
|
||||||
| Q6 | 重放期限与人工处置期限的取值(唯一作用是决定 `R_keep` 下界) | `R` = 30 天;重放/处置期限未定 | `R_keep` 取值 | 未确认 |
|
|
||||||
| Q7 | 处理标记值集与写权限、原文保留期、处理时间语义 | 写入 `PROCESSED` | 回填值集、保留期下界 | 未确认 |
|
| Q7 | 处理标记值集与写权限、原文保留期、处理时间语义 | 写入 `PROCESSED` | 回填值集、保留期下界 | 未确认 |
|
||||||
| Q8 | 逐类覆盖清单:真实报文的子类型分布、SIS 未定义的 legacy 子类型(`ABTM`/`DELY`/`PADT`/`FTSS`/`STND`/`BDPB`/`REMC`)的报文形态、逐类 golden、静态参考数据的批次暂存方式、admin-api 的数据库只读契约、除 FDEL 外目标航班不存在/已删除时的终态,以及 BOTM/LACL 运行状态的落点 | 航班动态的字段与空标签规则以 `SIS:3.19`~`SIS:3.43` 为准,静态参考数据以 `SIS:3.1`~`SIS:3.14` 的入站消息为准;SIS 未定义的行为不作统一推定 | 积压处置、逐类矩阵与参考数据发布、下游读取模型 | 暂缓(现阶段不处理) |
|
| Q8 | 逐类覆盖:SIS 未定义但现场会发的 7 类(靠桥、延误、计划机位等)的报文形态、除 FDEL 外目标航班不存在/已删除时的逐类终态、BOTM/LACL 运行状态的落点 | 航班动态的字段与空标签规则以 `SIS:3.19`~`SIS:3.43` 为准(`US-05` AC1 定案);静态参考数据以 `SIS:3.1`~`SIS:3.14` 为准(`US-13`);legacy 7 类按现有处理逻辑延续(`US-05` AC1 定案) | 逐类幂等矩阵与 golden(`G-FLOP-SEMANTICS`、`G-FLOP-IDEMPOTENT`、`G-REF-DATA`) | 未确认(不阻塞 `US-13` 验收) |
|
||||||
| Q9 | 清除执行方与 DDL 授权、方案 A/B 选型、分区能力 | 首选方案 A | `R_keep` 与清除边界 | 未确认 |
|
| Q9 | 清除执行方与 DDL 授权、方案 A/B 选型、分区能力 | 首选方案 A | `R_keep` 与清除边界 | 未确认 |
|
||||||
| Q10 | 出站消费方、ACK 列语义、出站清理与去重契约 | — | 出站信箱 | 未确认 |
|
| Q10 | 出站 ACK 列语义、出站行清理与去重契约 | — | 出站信箱 | 未确认 |
|
||||||
| Q11 | 上游 `SEQN` 重置周期与业务身份的日期边界 | 不含日期边界 | 身份算法 | 未确认 |
|
| Q11 | 上游 `SEQN` 重置周期与业务身份的日期边界 | 不含日期边界 | 身份算法 | 未确认 |
|
||||||
| Q12 | 积压批次「不再处理」的确认主体、审批留痕与跳过值集 | — | 积压跳过处置 | 未确认 |
|
| Q13 | 日计划缺失可选字段的删除语义 | 结论(2026-09-14):未携带字段视为 AODB 已删除该值,本地同步清除(`C-26`) | — | 已定案 |
|
||||||
| Q13 | 日计划缺失可选字段的删除语义 | 保留未携带字段;真实消息与 SIS 冲突时以真实消息为准 | 快照合并 | 暂缓(测试前不处理) |
|
| Q14 | 主/共享删除顺序与 EROR 回报义务 | 结论(2026-09-14):幂等原子级联、不回发 EROR(`C-25`) | — | 已定案 |
|
||||||
| Q14 | 主/共享删除顺序与 EROR 回报义务 | 幂等原子级联 | 出站事件类型 | 未确认 |
|
|
||||||
| Q15 | 上游是否会以同一业务身份改发正文(决定是否需要区分「重复」与「改发」) | 假定期望不可变(`C-4`) | 身份去重语义 | 未确认 |
|
| Q15 | 上游是否会以同一业务身份改发正文(决定是否需要区分「重复」与「改发」) | 假定期望不可变(`C-4`) | 身份去重语义 | 未确认 |
|
||||||
| Q16 | `FLID` 重用语义(决定版本是否按 incarnation 作用域) | 假定不复用(`C-21`) | 事件合并与 tombstone | 未确认 |
|
| Q16 | `FLID` 重用语义(决定版本是否按 incarnation 作用域) | 假定不复用(`C-21`) | 事件合并与 tombstone | 未确认 |
|
||||||
|
|
||||||
@@ -235,7 +249,7 @@ Q 的答复只在本表就地更新(补「结论」与日期),并触发 [R
|
|||||||
|
|
||||||
| 量 | 定义处 | 约束 |
|
| 量 | 定义处 | 约束 |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `R_keep` | `C-7` | `R_keep ≥ max(人工重放期限 + 人工处置期限, 审计期限, 回填重试上限)`;「重放窗口内原文仍在」的唯一保证来源 |
|
| `R_keep` | `C-7` | `R_keep ≥ max(审计期限, 回填重试上限)`;原文保留期下界(重放不在交付范围) |
|
||||||
| `R` | [reference.md](reference.md) `PARAM:msgx.pipeline.overdue-backfill` | `R ≤ R_keep`;只决定强补写与放弃期限,**不保护重放窗口** |
|
| `R` | [reference.md](reference.md) `PARAM:msgx.pipeline.overdue-backfill` | `R ≤ R_keep`;只决定强补写与放弃期限 |
|
||||||
| 去重记忆期 | `INV-9` | ≥ `R_keep`;否则「归档后重复」不成立 |
|
| 去重记忆期 | `INV-9` | = 处理记录保留期(`US-11`);期内同身份去重成立,期满后同身份消息按新消息处理 |
|
||||||
| 回填放弃清单可见期 | `C-16` | ≥ `R_keep`;否则库方清除缺 `C-8` 依据 |
|
| 回填放弃清单可见期 | `C-16` | ≥ `R_keep`;否则库方清除缺 `C-8` 依据 |
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ def main() -> int:
|
|||||||
# 参数与指标同表登记、语义不同,二者都算已登记
|
# 参数与指标同表登记、语义不同,二者都算已登记
|
||||||
REGISTRY = { # ID → (所属文件, 允许的定义小节)
|
REGISTRY = { # ID → (所属文件, 允许的定义小节)
|
||||||
"US": ("requirements.md", ["用户故事"]),
|
"US": ("requirements.md", ["用户故事"]),
|
||||||
"OPS": ("requirements.md", ["运行与切流验收", "需求覆盖与依赖"]),
|
"OPS": ("requirements.md", ["运行验收", "运行与切流验收", "需求覆盖与依赖"]),
|
||||||
"D": ("architecture.md", ["关键决策"]),
|
"D": ("architecture.md", ["关键决策"]),
|
||||||
"C": ("specification.md", ["契约"]),
|
"C": ("specification.md", ["契约"]),
|
||||||
"PRE": ("specification.md", ["前提"]),
|
"PRE": ("specification.md", ["前提"]),
|
||||||
|
|||||||
@@ -40,8 +40,7 @@ class PipelineProps {
|
|||||||
* 超期补写期限 R:一条消息到达终态后,过了这么久处理标记仍未写回信箱
|
* 超期补写期限 R:一条消息到达终态后,过了这么久处理标记仍未写回信箱
|
||||||
* (比如回填一直失败),扫描谓词的超期分支成立,无视退避强制补写(只会提前、从不推迟打标)。
|
* (比如回填一直失败),扫描谓词的超期分支成立,无视退避强制补写(只会提前、从不推迟打标)。
|
||||||
*
|
*
|
||||||
* 唯一约束是 R ≤ R_keep,**不保护重放窗口**(打标时刻与 R 解耦,完整论证见
|
* 唯一约束是 R ≤ R_keep(完整论证见 implementation.md「回填」)。确认之前不要为提速下调。
|
||||||
* design「回填」)。取值待 Q6 定案,确认之前不要为提速下调。
|
|
||||||
*/
|
*/
|
||||||
var overdueBackfill: Duration = Duration.ofDays(30)
|
var overdueBackfill: Duration = Duration.ofDays(30)
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ msgx:
|
|||||||
backoff-ms: [1000, 2000, 4000, 8000] # 指数退避;档位数必须 = max-attempts - 1(启动自检)
|
backoff-ms: [1000, 2000, 4000, 8000] # 指数退避;档位数必须 = max-attempts - 1(启动自检)
|
||||||
backoff-cap-ms: 60000
|
backoff-cap-ms: 60000
|
||||||
max-commit-delay: 5m # 空洞老化:W+1 空洞超过该时延判定为永久(Q2 最大提交时延)
|
max-commit-delay: 5m # 空洞老化:W+1 空洞超过该时延判定为永久(Q2 最大提交时延)
|
||||||
overdue-backfill: 30d # 超期补写期限 R(Q6):仅须 R ≤ R_keep,不保护重放窗口;判据比较本地 ENQUEUED_AT(implementation.md「回填」)
|
overdue-backfill: 30d # 超期补写期限 R:仅须 R ≤ R_keep;判据比较本地 ENQUEUED_AT(implementation.md「回填」)
|
||||||
backfill-batch: 100 # 回填扫描单批条数
|
backfill-batch: 100 # 回填扫描单批条数
|
||||||
backfill-max-attempts: 100 # 单行重试的告警阈值;放弃判据是 R 超期,不是次数(implementation.md「回填」)
|
backfill-max-attempts: 100 # 单行重试的告警阈值;放弃判据是 R 超期,不是次数(implementation.md「回填」)
|
||||||
# 一次性切流播种:默认(注释掉)不播种。min=读现存全部 | zero=从 0 按空洞规则 | max=跳过可见存量 | <id>
|
# 一次性切流播种:默认(注释掉)不播种。min=读现存全部 | zero=从 0 按空洞规则 | max=跳过可见存量 | <id>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@
|
|||||||
-- · 决策层:FLIGHT_SCHD + 8 张资源明细表 + FLIGHT_ROUTE_POINT —— 权威当前态(INV-11);
|
-- · 决策层:FLIGHT_SCHD + 8 张资源明细表 + FLIGHT_ROUTE_POINT —— 权威当前态(INV-11);
|
||||||
-- · 管道层:PIPELINE_LOCK / INBOX_CURSOR / PROC_STATE / MSG_EVENT / REQ_TRACK;
|
-- · 管道层:PIPELINE_LOCK / INBOX_CURSOR / PROC_STATE / MSG_EVENT / REQ_TRACK;
|
||||||
-- · 留痕层:SCHD_SNAP_LOG —— 只追加、可重建、不参与决策;
|
-- · 留痕层:SCHD_SNAP_LOG —— 只追加、可重建、不参与决策;
|
||||||
-- · 证据层:报文原文归档 —— 冷路径,尚未交付(ARCHIVE_KEY 仅留引用位,G-REPLAY-CHANNEL)。
|
-- · 证据层:报文原文归档 —— 冷路径,尚未交付(ARCHIVE_KEY 仅留引用位)。
|
||||||
-- 类型口径:TIMESTAMP(6) WITH TIME ZONE 统一 UTC 语义;BIGSERIAL 为 PostgreSQL 方言
|
-- 类型口径:TIMESTAMP(6) WITH TIME ZONE 统一 UTC 语义;BIGSERIAL 为 PostgreSQL 方言
|
||||||
-- (Oracle 11g 等价 DDL 见同目录 oracle11g/README.md)。
|
-- (Oracle 11g 等价 DDL 见同目录 oracle11g/README.md)。
|
||||||
-- =====================================================================
|
-- =====================================================================
|
||||||
@@ -41,7 +41,7 @@ INSERT INTO PIPELINE_LOCK (LOCK_ID, UPDATED_AT) VALUES (1, now());
|
|||||||
-- 状态不可逆:已提交的 SUCCEEDED 不因回填或投递失败回改(INV-6)。
|
-- 状态不可逆:已提交的 SUCCEEDED 不因回填或投递失败回改(INV-6)。
|
||||||
CREATE TABLE PROC_STATE (
|
CREATE TABLE PROC_STATE (
|
||||||
MSG_ID BIGINT NOT NULL PRIMARY KEY,
|
MSG_ID BIGINT NOT NULL PRIMARY KEY,
|
||||||
STATE VARCHAR(16) NOT NULL, -- PENDING/FAILED/SUCCEEDED/SKIPPED/DEAD(ARCHIVED 属未建归档能力 G-PROC-HST)
|
STATE VARCHAR(16) NOT NULL, -- PENDING/FAILED/SUCCEEDED/SKIPPED/DEAD
|
||||||
IDENTITY_KEY VARCHAR(200), -- SNDR|TYPE|STYP|SEQN,解码后首次绑定
|
IDENTITY_KEY VARCHAR(200), -- SNDR|TYPE|STYP|SEQN,解码后首次绑定
|
||||||
ATTEMPTS INT NOT NULL DEFAULT 0,
|
ATTEMPTS INT NOT NULL DEFAULT 0,
|
||||||
NEXT_ATTEMPT_AT TIMESTAMP(6) WITH TIME ZONE, -- 退避到期时刻;未到期不得被后续消息越过(INV-3)
|
NEXT_ATTEMPT_AT TIMESTAMP(6) WITH TIME ZONE, -- 退避到期时刻;未到期不得被后续消息越过(INV-3)
|
||||||
|
|||||||
Reference in New Issue
Block a user