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:
+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 内写入,是保留期判定的唯一基准。 |
|
||||
| `REQ_TRACK` | 上游请求及应答关联 | 状态 `PENDING / SENT / DONE / EXPIRED`;保存请求类型、覆盖运营日、发送方、出站信箱 ID 与发送/完成时间;**「同类只允许一个开放请求」的唯一键 = `(请求类型, 覆盖运营日, 发送方)`,且仅对开放状态生效**。 |
|
||||
| `REF_MASTER` | SIS 消息提供的静态参考数据与资源状态(目标表) | `(RTYPE, RKEY)` 唯一;`RTYPE` 类别、合并语义与资源状态见「静态参考数据」;取数路径见 [requirements.md](requirements.md) `US-13`。 |
|
||||
| `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)。 |
|
||||
| `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. 消息、身份与决策
|
||||
|
||||
@@ -44,15 +42,15 @@
|
||||
|
||||
**身份绑定是独立的幂等单语句**(`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. 状态与错误分类
|
||||
|
||||
```text
|
||||
处理:PENDING / FAILED → SUCCEEDED(成功)
|
||||
→ SKIPPED(业务重复、忽略、无匹配)
|
||||
→ SKIPPED(业务重复、忽略、不支持类型、无匹配)
|
||||
→ FAILED(等待退避重试)
|
||||
→ DEAD(MALFORMED / PROTOCOL / EXHAUSTED,均需人工处置)
|
||||
|
||||
@@ -61,47 +59,34 @@
|
||||
→ DEAD(重试耗尽,记录保留作 DLQ)
|
||||
```
|
||||
|
||||
`SUCCEEDED / SKIPPED / DEAD` 是处理终态,不再阻塞后续消息;`FAILED` 不是终态,仍占据队头。`DEAD` 表示需要处置,不等于业务成功。`ARCHIVED` 不是处理态:它是终态行归档后留在主表的去重影子行,不占队头、不触发回填、不参与积压聚合(见「生命周期与清除」)。
|
||||
`SUCCEEDED / SKIPPED / DEAD` 是处理终态,不再阻塞后续消息;`FAILED` 不是终态,仍占据队头。`DEAD` 表示需要处置,不等于业务成功。
|
||||
|
||||
重试次数用尽时统一转 `DEAD(EXHAUSTED)`:`ERROR_CLASS` 被覆写为 `EXHAUSTED`,原始错误类别不再保留(`LAST_ERROR` 保留原因文本)。重放白名单与错误分类表见 [reference.md](reference.md)「错误分类与重放白名单」。
|
||||
|
||||
## 4. 收报与水位
|
||||
## 4. 收报
|
||||
|
||||
### 4.1 收报流程
|
||||
|
||||
`InboxPoller` 按 ID 升序、有限批次读取水位之后的信箱记录(`ID > W`,**不以处理标记为谓词**),在自有 PG 建立 `PENDING` 并把水位推进到连续上界。每轮:
|
||||
`InboxPoller` 按配置周期查信箱中「处理标记为空」的行,按编号升序、每批有上限,在自有 PG 登记 `PENDING`(`INV-2b`)。每轮:
|
||||
|
||||
1. 读取游标 `(W, holeSince)`。信箱不可读时记日志、等下一轮,**不动水位**——这是基础设施失败,不能当成「没有新消息」。
|
||||
2. 取 `ID > W` 的升序前 `PARAM:msgx.pipeline.claim-batch` 行。
|
||||
3. 从 `W+1` 起逐 1 数,求连续上界;遇到第一个缺号即停止计数。
|
||||
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. 提交。本批因空洞或批次上限未入队的行留待下一轮——**每轮最多解决一个空洞**。
|
||||
1. 信箱不可读时记日志、等下一轮——这是基础设施失败,不能当成「没有新消息」。
|
||||
2. 取「处理标记为空」的行的升序前 `PARAM:msgx.pipeline.claim-batch` 条。
|
||||
3. 在同一个 PG 事务内对每一行 `insertIfAbsent(MSG_ID, RECEIVED_AT, ENQUEUED_AT)`;主键冲突表示已登记(重复扫描与兼容入口并发都安全),不计入、不报错。
|
||||
4. 提交。已打标的行不再出现在扫描结果里;终态但未回填的行会被重复读到,按已有记录幂等跳过。
|
||||
|
||||
`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`)。
|
||||
|
||||
### 4.4 兼容 HTTP 入口
|
||||
|
||||
`POST /cminmsgs/send` 执行「写入共享信箱 → PG 入队」,两步不在同一事务:信箱成功而 PG 失败时原文仍在信箱中,由轮询补建;客户端失败重试可能再次写信箱,业务身份去重仍然必需。该入口直接写 `PROC_STATE`、不读不推水位,登记的行因此**超出水位**;主泵只领 `MSG_ID ≤ W`,所以在水位追平前不会被处理——顺序不受影响,代价是延迟到追平,且必须让收报轮询运行。响应语义见 `C-28`。
|
||||
|
||||
### 4.5 单实例与水位
|
||||
|
||||
信箱读取不加锁,水位是单行覆盖写,本设计只在单活动实例下成立(`PRE-5`)。多实例并发收报会让水位互相覆盖(覆盖回退只会造成重复扫描,不会丢消息,但空洞计时会失真),必须先有实例级排他。
|
||||
信箱读取不加锁,本设计只在单活动实例下成立(`PRE-5`)。多实例并发扫描会重复登记同一行,主键幂等兜底不会丢消息,但实例级排他仍是前提。
|
||||
|
||||
## 5. 主泵调度与单条处理
|
||||
|
||||
@@ -110,14 +95,13 @@
|
||||
每次 `Pump.tick` 只围绕最小未完成消息:
|
||||
|
||||
1. 无队头:按轮询间隔休眠。
|
||||
2. 队头超出水位(`msgId > W`):**不领取**,休眠到下一轮。这类行只可能来自兼容入口的直接登记;允许领取会让它越过尚未入队的较小 ID。会打印一条限流 WARN(仅在水位值变化时打一次)。
|
||||
3. 队头为 `FAILED` 且尝试次数达上限:转 `DEAD(EXHAUSTED)`,终态与回填意图同一条 UPDATE 落库,**不做跨库写**。该分支只写 `PROC_STATE`,不取 `PIPELINE_LOCK`、不在处理器事务内,也不在 `MessageLifecycleGate` 内。
|
||||
4. 队头为 `FAILED` 且未到 `next_attempt_at`:休眠到可重试时刻,不处理后续消息。
|
||||
5. 其余(新消息或退避到期的重试):调用 `MessageProcessor.processOne`,失败迁移在该边界内完成。
|
||||
2. 队头为 `FAILED` 且尝试次数达上限:转 `DEAD(EXHAUSTED)`,终态与回填意图同一条 UPDATE 落库,**不做跨库写**。该分支只写 `PROC_STATE`,不取 `PIPELINE_LOCK`、不在处理器事务内,也不在 `MessageLifecycleGate` 内。
|
||||
3. 队头为 `FAILED` 且未到 `next_attempt_at`:休眠到可重试时刻,不处理后续消息。
|
||||
4. 其余(新消息或退避到期的重试):调用 `MessageProcessor.processOne`,失败迁移在该边界内完成。
|
||||
|
||||
**终态判据只有尝试上限,没有按时间的毒丸**:处理卡死应由外部调用的有界超时兜底;用一个时间阈值把消息直接推入 `DEAD` 会绕过人工复核,并制造与人工重放并发的旁路写入者。队头年龄由 `msgx.pipeline.backlog.oldest_unprocessed_seconds` 观测,主泵不做这项判定。
|
||||
|
||||
**所有取时统一经注入 `Clock`**(收报空洞老化、主泵调度、处理器落库时间、回填重试、作业切日),不使用系统时钟。
|
||||
**所有取时统一经注入 `Clock`**(主泵调度、处理器落库时间、回填重试、作业切日),不使用系统时钟。
|
||||
|
||||
### 5.2 processOne
|
||||
|
||||
@@ -131,31 +115,29 @@ processOne(head):
|
||||
已被本消息占用 → 继续
|
||||
已被别的消息占用 → SKIPPED(duplicate-of:<id>),结束
|
||||
空闲 → 写入 IDENTITY_KEY(独立单语句,不参与业务事务)
|
||||
4. 忽略规则命中 → SKIPPED(ignored:<rule>)(非业务型终态)
|
||||
5. 按 MsgKind 分派:
|
||||
4. 按 MsgKind 分派:
|
||||
SCHD-DNLD / SCHD-RESP → ScheduleProcessor(快照事务)
|
||||
SCHD-ADFT → AdftProcessor(单航班事务)
|
||||
FLOP / FDEL → Flop / FdelProcessor(单航班事务)
|
||||
Unsupported → FAILED(UNSUPPORTED) 退避
|
||||
Unsupported → SKIPPED(unsupported)(跳过留档,按已处理写回标记)
|
||||
载荷缺失 → DEAD(MALFORMED)
|
||||
整包协议拒绝 → DEAD(PROTOCOL),不落半包
|
||||
6. 业务型成功:处理器在自己的事务内写航班变更 + 待发事件 + SUCCEEDED + 回填意图
|
||||
7. 结束:主泵不做回填;回填意图已随终态落库,由扫描补写信箱标记
|
||||
5. 业务型成功:处理器在自己的事务内写航班变更 + 待发事件 + SUCCEEDED + 回填意图
|
||||
6. 结束:主泵不做回填;回填意图已随终态落库,由扫描补写信箱标记
|
||||
```
|
||||
|
||||
- 原文缺失归为 `MALFORMED`;读取异常按基础设施失败进入重试,与「原文缺失」区分。
|
||||
- 类型未覆盖不等于报文非法:忽略类报文在规则实现前不按 `MALFORMED` 处理。
|
||||
- 类型未覆盖不等于报文非法:不支持的消息类型跳过留档、按已处理写回标记,不按 `MALFORMED` 处理。
|
||||
- **主泵不回填**:终态与回填意图由同一条 UPDATE 落库,回填一律由扫描驱动,不占用 FIFO 关键路径。回填只需消息 ID,缺 META 或解码失败的死信同样可补写。影子环境禁写。
|
||||
|
||||
### 5.3 事务边界
|
||||
|
||||
| 动作 | 显式事务 | 持 `PIPELINE_LOCK` | 触及航班表 / 事件 | 原子性来源 |
|
||||
|---|---|---|---|---|
|
||||
| 收报入队(`insertIfAbsent` + `cursor.save`) | 是 | 否 | 否 | 同库事务 |
|
||||
| 收报入队(`insertIfAbsent`) | 是 | 否 | 否 | 同库事务 |
|
||||
| 身份首次绑定 | 否 | 否 | 否 | 单语句 + 唯一约束 |
|
||||
| 业务型终态(处理器产出 `SUCCEEDED`) | 是 | 是 | 是 | 同库事务:航班变更 + 事件 + 终态 + 回填意图 |
|
||||
| 非业务型终态(`MALFORMED` / `PROTOCOL` / `SKIPPED` / `EXHAUSTED`) | 否 | 否 | 否 | 单语句(终态与回填意图同一条 UPDATE) |
|
||||
| 航班历史清理的物理删除 | 是 | 是(`INV-18`) | 是 | 同库事务:复查判据 + 归档成功后删除 |
|
||||
| 航班历史清理的物理删除 | 是 | 是(`INV-18`) | 是 | 同库事务:复查判据 + 历史写入成功后删除 |
|
||||
| 回填(信箱标记 + `BACKFILL_AT`) | 否 | 否 | 否 | 跨库两次单写;幂等可重跑 |
|
||||
| 人工重放(批量改回 `PENDING`) | 否 | 否 | 否 | 单语句批量;`MessageLifecycleGate` 与回填互斥 |
|
||||
|
||||
@@ -168,7 +150,7 @@ processOne(head):
|
||||
- 顺序由 `MSG_ID` 决定,不由执行方式决定。入队与处理由不同线程驱动、可以并发,「先入队后处理」只是可选的运维规程,不是正确性前提;系统不提供「只入队」模式。
|
||||
- 不加速、不分流、不走旁路:不允许并行队头,也不允许实时消息跳过积压。
|
||||
- 尝试上限与退避对积压同样生效,不因积压而放宽。
|
||||
- 经确认不再处理的行置 `SKIPPED` 并记录原因,到达终态后走回填通道;不存在「整段 DELETE」的快速通道(授权与留痕见 `C-27`/`Q12`)。
|
||||
- 不再处理的行置 `SKIPPED` 并记录原因,到达终态后走回填通道;不存在「整段 DELETE」的快速通道。
|
||||
- 消化期间的可观测项与完成时限口径见 [reference.md](reference.md) 与 `CLM-9`:**扫描周期不是完成时限**。
|
||||
|
||||
## 6. 回填
|
||||
@@ -216,9 +198,9 @@ LIMIT PARAM:msgx.pipeline.backfill-batch
|
||||
2. 到 `R` 仍失败则停止自动重试、告警,进入放弃清单,保留人工恢复(`reopen`);
|
||||
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. 日计划快照与请求匹配
|
||||
|
||||
@@ -226,10 +208,10 @@ LIMIT PARAM:msgx.pipeline.backfill-batch
|
||||
|
||||
`SCHD-DNLD` 与 `SCHD-RESP` 共用 `ScheduleProcessor.applyScheduleRecords`:
|
||||
|
||||
1. **重放判定**:`PROC_STATE` 已存在成功终态 → 幂等成功,仅追加留痕,不重复写入。
|
||||
1. **重复处理判定**:`PROC_STATE` 已存在成功终态 → 幂等成功,仅追加留痕,不重复写入。
|
||||
2. **整包校验**:声明记录数、航班标识与运营日推导等校验失败 → 整包 `DEAD(PROTOCOL)`,不写半包,既有状态保持不变。
|
||||
3. **事务写入**:锁内按 `FLID` 点查归属日,发现同一航班跨运营日即整包回滚并 `DEAD(PROTOCOL)`;通过后合并写主表与资源明细。报文未携带的航班不因本次日计划报文被删除。
|
||||
4. **提交结果**:同一事务保存 `KAFKA:schd` / `KAFKA:msg` 事件、置消息 `SUCCEEDED` 并预登记回填意图;提交后信箱回填由扫描承接,留痕在事务外追加。
|
||||
3. **分批写入**:锁内按 `FLID` 点查归属日,发现同一航班跨运营日即整包回滚并 `DEAD(PROTOCOL)`;通过后分批合并写主表与资源明细,每批一个事务(状态变更 + 待发事件,`INV-17b`)。快照里没有的航班删除:标记已删除、登记删除事件、从 Redis 投影移除(`INV-15b`)。
|
||||
4. **提交结果**:整包完成后在同一事务置消息 `SUCCEEDED` 并预登记回填意图;提交后信箱回填由扫描承接,留痕在事务外追加。处理失败不标记已处理,下轮整包重新处理。
|
||||
|
||||
字段缺失与清空语义、运营日规则见「航班域」。
|
||||
|
||||
@@ -299,12 +281,10 @@ PENDING → SENT → DONE
|
||||
|
||||
| 中断位置 | 重启后的判定 | 恢复动作 |
|
||||
|---|---|---|
|
||||
| 已落信、未入队 | 信箱行位于应扫描的 ID 范围且 PG 无记录(不以处理标记为判据) | 重扫补建入队记录 |
|
||||
| 水位卡在空洞 | `HOLE_SINCE` 有值且未超过 `PARAM:msgx.pipeline.max-commit-delay` | 等待;超期后放行空洞本身并继续推进 |
|
||||
| 已落信、未入队 | 信箱行处理标记为空且 PG 无记录 | 重扫补建登记记录 |
|
||||
| 事务执行中 | PG 无该消息终态 | 事务整体回滚,按 `PENDING` 重新处理 |
|
||||
| 事务已提交、标记未写 | 终态行仍持有回填意图 | 仅补写标记;业务处理结果保持不变 |
|
||||
| 标记写入中途 | 标记仍为空 | 重新写入;重复写入同一值无副作用 |
|
||||
| 兼容入口已入队、水位未追平 | PG 已有该 ID 的记录 | 轮询读到该行时主键幂等,水位照常推进 |
|
||||
| 回填时信箱行已不存在 | 写入 0 行且信箱行不存在 | 立即放弃自动重试(`MISSING_ROW`)并告警;放弃不等于标记已确认,仍需人工对账 |
|
||||
| `RECEIVED_AT` 为 NULL | 超期分支以本地 `ENQUEUED_AT` 判定,不受库方时钟与 NULL 影响 | 按 `R` 超期强补写;未超期则按退避重试 |
|
||||
| 投递目标已接受、`SENT` 未置 | 事件仍 `PENDING` | 允许重发,消费方按事件身份去重 |
|
||||
@@ -316,40 +296,36 @@ PENDING → SENT → DONE
|
||||
|
||||
**通则**(对本系统所有持久对象适用)
|
||||
|
||||
- **时间不构成清除依据**:到期只是必要条件,**终局证据才是充分条件**(共享库见 `C-8`,航班见 `D1`)。
|
||||
- **归档不是终点**:归档目标是新的无界集合,必须有独立保留期与清除作业 `G-HST-RETENTION`,否则只是把容量问题从热表移到冷表。
|
||||
- **时间不构成清除依据**:到期只是必要条件,**终局证据才是充分条件**(共享库见 `C-8`,航班见 `INV-28`)。
|
||||
- **证据不随清除消失**:清除所依赖的证据(如 `C-8` 引用的回填放弃清单,本期承诺见 `C-16`)在其覆盖的信箱边界被清除前必须保持可查。
|
||||
- **证据缺失或结果不明时按最保守处置**:航班清理为删 0 条(`D1`)。
|
||||
- **证据缺失或结果不明时按最保守处置**:航班清理为删 0 条(`INV-28`)。
|
||||
|
||||
**逐对象生命周期**(保留期取值一律见 [reference.md](reference.md))
|
||||
|
||||
| 对象 | 终局判据 | 归档目标 | 清除证据 | 执行方 | 偏差 |
|
||||
|---|---|---|---|---|---|
|
||||
| 共享信箱 `CMINMSGS` 原文 | 处理标记 / 回填放弃清单 | 库方历史表(`C-9` 方案 B) | `C-8` | 库方 | 契约未确认(`Q6`/`Q7`/`Q9`) |
|
||||
| `FLIGHT_SCHD` + 资源明细 | 判史规则 | 历史存储 | 归档确认 + 版本复查 | 我们 | — |
|
||||
| 共享信箱 `CMINMSGS` 原文 | 处理标记 / 回填放弃清单 | — | `C-8` | 库方 | 契约未确认(`Q7`/`Q9`) |
|
||||
| `FLIGHT_SCHD` + 资源明细 | 判史规则 | 历史存储 | 历史写入确认 + 版本复查 | 我们 | — |
|
||||
| 航班历史存储 | 保留期 | — | — | 我们 | `G-FLIGHT-HIST-RETENTION` |
|
||||
| `SCHD_SNAP_LOG` | 保留期 | 无(本地可重建) | 无 | 我们 | — |
|
||||
| `MSG_EVENT` 已发送行 | `SENT` | 无 | 无 | 我们 | — |
|
||||
| `PROC_STATE` 终态行 | 见下 | `PROC_STATE_HST` | 回填了结 | 我们 | `G-PROC-HST` |
|
||||
| `PROC_STATE_HST` | 保留期 | — | — | 我们 | `G-HST-RETENTION` |
|
||||
| `PROC_STATE` 终态行 | 见下 | 无(到期直接删除) | 回填了结 | 我们 | `G-PROC-CLEANUP` |
|
||||
| `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` 的清除授权证据,未对账前不得归档。
|
||||
- **写入前复查** = `DEAD` 可被人工重放改回 `PENDING`。人工重放走 `MessageLifecycleGate`、不取 `PIPELINE_LOCK`,因此该锁不构成复查依据:归档在同一事务内先 `INSERT INTO PROC_STATE_HST … SELECT`,再按候选时的 `STATE` 条件写主表;影响 0 行即整体回滚、该行跳过。重放先一步改回 `PENDING` 时谓词不匹配,天然互斥。批量归档不得持 `PIPELINE_LOCK`——那会阻塞主泵 FIFO,与「作业不使到期消息饥饿」冲突。
|
||||
清理范围只含「终态且已回填」;保留期内同身份去重成立(`INV-9`),保留期过后同身份消息按新消息处理(去重记忆期 = 保留期,见 [specification.md](specification.md)「契约数值」)。
|
||||
|
||||
归档范围只含终态;归档后仍须保留业务去重能力(`INV-9`)——去重记忆期长于工作状态在线期,实现取「主表保留去重影子行」:主行置 `STATE='ARCHIVED'`、只留 `IDENTITY_KEY` 与 `MSG_ID`,`IDENTITY_KEY` 唯一约束留在主表不动。队头推进、`backlog()` 与回填扫描的谓词显式排除 `ARCHIVED`,不靠状态包含列表隐式过滤。
|
||||
|
||||
**时间常数排序**:`R ≤ R_keep`、去重记忆期 ≥ `R_keep`、放弃清单可见期 ≥ `R_keep` 三个下界关系的定义与理由见 [specification.md](specification.md)「契约数值」,本文件不复述。只补一条实现口径:归档阈值计的是**终局之后**的时间,不是入队之后——终态行未了结回填时不进入候选。
|
||||
**时间常数排序**:`R ≤ 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)` 删除,不依赖历史存储开关。
|
||||
- **出站事件清理**:见「事件清理」。
|
||||
|
||||
@@ -363,18 +339,18 @@ PENDING → SENT → DONE
|
||||
- 处理延迟秒级可接受;航班可见性延迟不劣于现役(轮询间隔 + 聚合周期秒级)。
|
||||
- 因此:不引入多实例并行、分布式锁、分区表;用单行锁与单线程换确定性。
|
||||
|
||||
容量假设变化时,需要重新评估的项:批次大小与轮询间隔、聚合周期与批上限、指标取数口径(`backlog()` 是 `PROC_STATE` 聚合;`G-PROC-HST`)、以及 `MSG_EVENT` 保留期。
|
||||
容量假设变化时,需要重新评估的项:批次大小与轮询间隔、聚合周期与批上限、指标取数口径(`backlog()` 是 `PROC_STATE` 聚合)、以及 `MSG_EVENT` 保留期。
|
||||
|
||||
## 11. 航班域:权威模型与合并写入语义
|
||||
|
||||
本章是航班状态的唯一现行设计规范。其他各章只描述管道机制,不重复定义航班域规则。
|
||||
|
||||
系统从共享 MySQL 信箱接收 SIS/AODB 报文,把结果合并到自有 PostgreSQL 中的航班当前态,再通过 outbox 投递 Kafka。共享信箱和 Kafka 都不是状态权威,也不在本地事务的提交范围内。
|
||||
系统从共享 MySQL 信箱接收 SIS/AODB 报文,把结果合并到自有 PostgreSQL 中的航班当前态并同步写 Redis 投影,再通过 outbox 投递 Kafka。共享信箱、Redis 投影和 Kafka 都不是状态权威;Redis 投影写在处理完成之前(`INV-23`)。
|
||||
|
||||
- `FLID` 是航班实例的唯一标识;不得由航班号、日期或资源号推断身份。
|
||||
- `FLIGHT_SCHD` 及其明细表是唯一权威当前态;展示视图只读,不能作为写入或对账来源(`INV-11`)。
|
||||
- `FLIGHT_SCHD` 及其明细表是唯一权威当前态;Redis 投影与展示视图只读,不能作为写入或对账来源(`INV-11b`)。
|
||||
- 单活动主泵按信箱 FIFO 推进。事务内 `PIPELINE_LOCK` 只串行化本地状态提交,不替代选主或消息认领。
|
||||
- 状态写入、outbox 事件、处理终态和回填意图在同一 PostgreSQL 事务中提交(`INV-17`);回填与 Kafka 投递在提交后独立重试。
|
||||
- 状态变更与 outbox 事件在同一 PostgreSQL 事务中提交;处理终态与回填意图在同一事务中提交、且晚于 Redis 投影写成功(`INV-17b`);回填与 Kafka 投递在提交后独立重试。
|
||||
|
||||
### 11.1 权威模型
|
||||
|
||||
@@ -385,7 +361,6 @@ PENDING → SENT → DONE
|
||||
| `FLIGHT_ROUTE_POINT` | ROUT 与 ERUT 两类路线点,使用 `ROUTE_KIND` 区分;主键应包含该列,避免两类路线的序号冲突。 |
|
||||
| `PROC_STATE` | 信箱消息的处理终态、业务身份幂等记录,以及回填事实(`RECEIVED_AT` / `BACKFILL_*`)。 |
|
||||
| `MSG_EVENT` | 事务 outbox,承载整态投影、变更通知和删除 tombstone。 |
|
||||
| `INBOX_CURSOR` | 共享信箱消费水位(读取进度,与处理标记互不替代)。 |
|
||||
| `SCHD_SNAP_LOG` | 日计划处理留痕,只追加、可重建,不参与状态决策。 |
|
||||
|
||||
### 11.2 航班身份与运营日
|
||||
@@ -445,21 +420,19 @@ PENDING → SENT → DONE
|
||||
|
||||
## 12. 航班域:合并、删除与生命周期
|
||||
|
||||
本章的领域规则只描述「合并成什么态」;决策纯度、事务边界与落库职责见「消息、身份与决策」与 `INV-17`(`US-03`)。
|
||||
本章的领域规则只描述「合并成什么态」;决策纯度、事务边界与落库职责见「消息、身份与决策」与 `INV-17b`(`US-03`)。
|
||||
|
||||
### 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)
|
||||
|
||||
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 为准;下表每一行都必须有一条回归用例钉住「输入与前态 → 目标状态 → 终态与事件」。
|
||||
|
||||
@@ -470,9 +443,9 @@ FLOP 只修改报文表达的字段或集合,其余状态保持不变;目标
|
||||
| `SIS:3.21` | `BOTM` | `BOTM` 标量;非空时设置登机状态 | 空 = 清除登机时间并重置登机状态 |
|
||||
| `SIS:3.22` | `CHOT` | `CHOT` 集合 | 集合按完整结果替换;元素内 `CHTM` 空 = 删除该轮挡时间 |
|
||||
| `SIS:3.23` | `FLTY` | `FLTY` 标量 | 字段为 M,未写明空语义 |
|
||||
| `SIS:3.24` | `CKDT` | `CKDT` 集合 | 空 `<CKDT CKNO="0">` = 现无柜台分配;**AODB 方向报文必须拒绝** |
|
||||
| `SIS:3.25` | `CLDT` | `CLDT` 集合 | 空 `<CLDT CLNO="0">` = 现无转盘分配;**AODB 方向报文必须拒绝** |
|
||||
| `SIS:3.26` | `CHDT` | `CHDT` 集合 | 空 `<CHDT CHNO="0">` = 现无滑槽分配;**AODB 方向报文必须拒绝** |
|
||||
| `SIS:3.24` | `CKDT` | `CKDT` 集合 | 空 `<CKDT CKNO="0">` = 现无柜台分配;AODB 实际会发,照常接收处理(`US-05` AC3) |
|
||||
| `SIS:3.25` | `CLDT` | `CLDT` 集合 | 空 `<CLDT CLNO="0">` = 现无转盘分配;AODB 实际会发,照常接收处理(`US-05` AC3) |
|
||||
| `SIS:3.26` | `CHDT` | `CHDT` 集合 | 空 `<CHDT CHNO="0">` = 现无滑槽分配;AODB 实际会发,照常接收处理(`US-05` AC3) |
|
||||
| `SIS:3.27` | `CNCL` | `CNCL` 标量 | 空 = **撤销**上一次取消(不是清空时间) |
|
||||
| `SIS:3.28` | `ESTT` | `ESTT` 标量 | 空 = 删除预计时间 |
|
||||
| `SIS:3.29` | `FDEL` | 走删除路径(「删除与重建」) | 恒为空标签 |
|
||||
@@ -480,18 +453,18 @@ FLOP 只修改报文表达的字段或集合,其余状态保持不变;目标
|
||||
| `SIS:3.31` | `FINT` | `FINT` 标量 | 空 = 删除最终时间 |
|
||||
| `SIS:3.32` | `FLIN` | `FLIN` 标量 | 字段为 M,未写明空语义 |
|
||||
| `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.36` | `MAXP` | `MAXP` 标量 | 空 = 删除最大载客数 |
|
||||
| `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.40` | `ROUT` | `ROUT` 集合 | `SCAT`/`SCDT` 分别对起点/终点缺席;RMS 只保留 4 条(离港取前 4、到港取后 4)且不保存 `SCAT`/`SCDT` |
|
||||
| `SIS:3.41` | `TAOP` | `TAOP`/`TAFL`/`TAID` 标量 | 任一为空 = 该到达航班的经停连接断开 |
|
||||
| `SIS:3.42` | `TRML` | `TRML` 标量 | 空 = 删除航站楼 |
|
||||
| `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 行为直接定案。
|
||||
|
||||
@@ -504,14 +477,13 @@ FLOP 只修改报文表达的字段或集合,其余状态保持不变;目标
|
||||
### 12.3 删除与重建
|
||||
|
||||
FDEL 是业务删除入口:仅在 `ACTIVE → DELETED` 时推进版本、保留明细并与 tombstone 同事务登记;重复 FDEL 或不存在的航班按幂等成功处理。
|
||||
|
||||
物理删除仅由独立历史清理在归档成功后执行(`D1`)。日计划报文不是删除依据(`INV-15`)。若未经 FDEL 而由生命周期清理,清理前需要登记一次 tombstone;已经 FDEL 的记录不重复发出。
|
||||
物理删除仅由独立历史清理在历史写入成功后执行(`INV-28`)。快照里没有的航班删除(`INV-15b`);FDEL 仍是最先的删除入口。清理前需要登记一次 tombstone;已经 FDEL 的记录不重复发出。
|
||||
|
||||
ADFT 的字段缺失语义尚待上游确认。在确认前采用保守的 Set-only 规则:出现字段可更新,缺失字段不清空;不得把它当成日计划或动态全量替换。新建 ADFT 若带可解析的 `SODT`,按同一运营日规则计算 `OPERATION_DAY`;否则保留为 `NULL`。
|
||||
|
||||
主/共享航班级联:删除共享航班时重算主航班 `MAFL`(见「主/共享投影」)并向主航班通知;删除主航班时级联删除其子共享关联并发出删除通知;主/共享关系必须一次原子变更,不出现主已删、子残留的半状态。共享航班增量通常只更新并通知主航班,不直接发共享通知。这些语义同样约束 FDEL 之外的生命周期清理。主/共享关联的增删按 `FLID` 做值比较,不使用引用比较。
|
||||
|
||||
本章的原子级联不回发 EROR,与 SIS 的删除顺序要求相反;取舍见 `C-25`、`Q14`。
|
||||
本章的原子级联不回发 EROR(`C-25`、`Q14` 已定案)。
|
||||
|
||||
### 12.4 Kafka 与读取
|
||||
|
||||
@@ -560,7 +532,7 @@ ADFT 的字段缺失语义尚待上游确认。在确认前采用保守的 Set-o
|
||||
|
||||
### 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`。
|
||||
- **资源状态**:`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,不读取其数据库或缓存。
|
||||
- admin-api 只读取已提交的航班状态与 `REF_MASTER` 有效视图,不参与消息解码、合并、批次发布或处理终态判定。
|
||||
- 开发运行时使用自有 PostgreSQL;Oracle 只有通过 `Q1` 要求的方言与集成验证后才可替代,单次部署不得同时把两库作为权威。
|
||||
- admin-api 的物理读取契约在 `Q8` 定案;共享 MySQL 始终只是信箱边界,不承载该读取模型。
|
||||
- admin-api 直接读取本系统写入的静态参考数据表(`C-31`);共享 MySQL 始终只是信箱边界,不承载该读取模型。
|
||||
|
||||
Reference in New Issue
Block a user