# 实现设计 msgexchange-v2 怎么处理报文:记录模型、状态机、事务边界、航班与静态参考数据合并规则。 对外术语见 [specification.md](specification.md)「术语」;本文保留管道内部说法(队头、终态、回填意图)。参数见 [reference.md](reference.md) `PARAM:<键>`;不变量见 `INV-x`/`C-x`;能否对外承诺见 specification「声明边界」。不写交付进度。 三块:**管道**(收报→主泵→写回→Kafka)、**航班域**(PG + Redis 快照)、**静态参考数据**(`REF_MASTER`)。 ## 1. 术语与持久化记录 ### 1.1 管道术语 | 术语 | 语义 | |---|---| | 扫描谓词 | 读信箱时只取「处理时间为空」的行(`INV-1`);不用 ID 区间或水位当消费边界。 | | 队头 | 编号最小的未完成消息(`PENDING` 与 `FAILED` 都占位)。 | | 终态 | `SUCCEEDED` / `SKIPPED` / `DEAD`;到达后后面的消息才能处理。 | | 回填 / 回填意图 | 写回处理时间的实现机制([specification.md](specification.md)「写回处理时间」)。`BACKFILL_*` 列记录进度;`BACKFILL_NEXT_AT` 非空 = 还欠一次写回。意图与终态同一条语句落库,且在 Redis 航班快照写成功之后(`INV-10`)。 | | `R`、`R_keep`、处理标记 | 定义见 [specification.md](specification.md)。 | ### 1.2 持久化记录 | 记录 | 用途 | 关键约束 | |---|---|---| | `PROC_STATE` | 消息处理状态、身份、重试、错误、回填 | `MSG_ID` 主键;`IDENTITY_KEY` 唯一;最小未完成 `MSG_ID` = 队头。`BACKFILL_NEXT_AT` 非空 = 待写回;`BACKFILL_AT` 非空 = 已写回;`BACKFILL_ABANDONED_*` 非空 = 停自动重试(≠ 已写回)。`ENQUEUED_AT` 非空,超期只看它;`RECEIVED_AT` 可 NULL,仅对账。 | | `MSG_EVENT` | 待发 Kafka 事件(outbox) | `TARGET` = `KAFKA:msg` / `KAFKA:schd`。`msg`:`EVENT_ID` 稳定、保序。`schd`:按 `FLID` 单行 upsert,每次更新换 `EVENT_ID`。`SENT_AT` 与投递确认同事务写入,保留期从它起算。 | | `REQ_TRACK` | 出站请求与应答 | 状态 `PENDING/SENT/DONE/EXPIRED/FAILED`。开放槽:`RQRD` 与 `RQFD` 各一条(`US-09` AC1),不是 14 类 `STYP` 各一条。`OMMS` 发送(`C-4`)。结案态关闭槽。 | | `REF_MASTER` | SIS 消息提供的静态参考数据与资源状态的逻辑视图(物理为独立数据表组) | `(RTYPE, RKEY)` 唯一;`RTYPE` 类别、合并语义与资源状态见「静态参考数据」;取数路径见 [requirements.md](requirements.md) `US-13`。 | | `FLIGHT_SCHD` | 航班标量及单值异常字段 | `FLID` 主键;运营日与版本、最近消息 ID 用于追踪。变长集合存于资源明细表与 `FLIGHT_ROUTE_POINT`,规则见「航班域」。 | | `SCHD_SNAP_LOG` | 日计划处理留痕 | 只追加、可重建,不参与状态决策;保留期见 [reference.md](reference.md)。 | 字段与索引以 `src/main/resources/db/migration/` 为准。原文读共享信箱;清理见 `C-1`。 ## 2. 消息、身份与决策 `XmlCodec` 解码 XML → `DecodedMessage`(元数据 + `MsgKind` + 载荷)。`MALFORMED` 不重试;`CODEC_ERROR` 可退避重试。分派键:`Schd`、`Flop`、`Fdel`、`RefData`(`SIS:3.1`~`3.15`)、`Unsupported`。 身份 `Identity.of` = `SNDR|TYPE|STYP|SEQN`(`C-3`)。入队只按信箱 ID 去重;解码后首次绑定,重试不改绑定。占用 → `SKIPPED(duplicate-of:)`。日期边界见 `PARAM:msgx.identity.include-day-boundary`;上线后不可换算法。绑定是独立单语句(`IDENTITY_KEY IS NULL`),只认身份不比正文。 `MessageProcessor` 按 `MsgKind` 分派队头消息: | `MsgKind` | 处理器 | |---|---| | SCHD-DNLD/RESP | `ScheduleProcessor` | | SCHD-ADFT | `AdftProcessor` | | FLOP | `FlopProcessor` | | FDEL | `FdelProcessor` | | RefData 3.1~3.14 / 3.15 配对 | `ReferenceDataProcessor` | | 其余 | `SKIPPED(unsupported)` | 处理器在 `PIPELINE_LOCK` 内读态、算下一态与待发事件 → 提交 → 写 Redis → 另事务写终态与回填意图(`INV-3`、`INV-10`)。不直接发 Kafka。锁跨 Redis 写,覆盖历史清理协作(`US-14` AC4)。 不支持类型:跳过留档(`US-03` AC2)。`REGN`/`RSTA` 必须走 `US-13`,不得跳过。 ## 3. 状态与错误分类 ```text 处理:PENDING / FAILED → SUCCEEDED(成功) → SKIPPED(业务重复、忽略、不支持类型、无匹配) → FAILED(等待退避重试) → DEAD(MALFORMED / PROTOCOL / EXHAUSTED,均需人工处置) 投递:PENDING → SENT → PENDING(退避后重试) → DEAD(重试耗尽,记录保留作死信) ``` `SUCCEEDED`/`SKIPPED`/`DEAD` 是终态,不挡后续;`FAILED` 仍占队头。用尽重试 → `DEAD(EXHAUSTED)`。错误分类与重放白名单见 [reference.md](reference.md)。 ## 4. 收报 ### 4.1 收报 `InboxPoller` 周期扫描「处理时间为空」的行,升序、每批 `PARAM:msgx.pipeline.claim-batch` 条,在 PG 建 `PENDING` 记录(`INV-1`): 1. 信箱不可读 → 记日志,下轮再试(不是「无新消息」)。 2. 同事务 `insertIfAbsent(MSG_ID, RECEIVED_AT, ENQUEUED_AT)`;冲突 = 已有记录,跳过。 3. 已写回处理时间的行不再出现;终态未写回的行会重复扫到,幂等跳过。 写回延迟期间扫描量会涨,须观测积压([reference.md](reference.md) 指标)。 信箱 ID 单调不复用(`INV-1`)。`POST /cminmsgs/send` 与 adapter 同路径(`C-7`)。单活动实例(`OPS-1`);多实例靠主键幂等,仍须单实例排他。 ## 5. 主泵调度与单条处理 ### 5.1 调度 `Pump.tick` 只处理队头(最小未完成 `MSG_ID`): 1. 无队头 → 休眠。 2. `FAILED` 且次数用尽 → `DEAD(EXHAUSTED)`,同事 UPDATE 写终态与回填意图;只写 `PROC_STATE`,不取锁。 3. `FAILED` 且未到 `next_attempt_at` → 等到点,不跳队。 4. 其余 → `MessageProcessor.processOne`。 不按时间推 `DEAD`;卡死靠外部有界超时。队头年龄见指标 `msgx.pipeline.backlog.oldest_unprocessed_seconds`。时间一律用注入 `Clock`。 ### 5.2 processOne ```text processOne(head): 1. 读原文:缺失 → DEAD(MALFORMED, raw-missing);读取异常 → FAILED(INFRA) 2. 解码: 报文非法(MALFORMED) → DEAD(MALFORMED),不重试 可修复解码错(CODEC_ERROR) → FAILED(CODEC_ERROR) 退避 3. 身份绑定(仅当 IDENTITY_KEY 为空): 已被本消息占用 → 继续 已被别的消息占用 → SKIPPED(duplicate-of:),结束 空闲 → 写入 IDENTITY_KEY(独立单语句,不参与业务事务) 4. 按 MsgKind 分派: SCHD-DNLD / SCHD-RESP → ScheduleProcessor(快照事务) SCHD-ADFT → AdftProcessor(单航班事务) FLOP / FDEL → Flop / FdelProcessor(单航班事务) RefData(SIS:3.1~3.14 落库;SIS:3.15 闭合 REQ_TRACK) → ReferenceDataProcessor Unsupported → SKIPPED(unsupported)(跳过留档,按已处理写回标记) 载荷缺失 → DEAD(MALFORMED) 整包协议拒绝 → DEAD(PROTOCOL),不落半包 5. 业务型成功,分三步(INV-3、INV-10): ① 事务提交:航班变更 + 待发事件 ② 写 Redis 航班快照;失败 → 保持未完成,下轮重处理 ③ 事务提交:SUCCEEDED + 回填意图 6. 结束:主泵不做回填;回填意图已随终态落库,由扫描补写信箱标记 ``` 不支持类型 ≠ 报文非法,走 `SKIPPED`。主泵不写回信箱;写回由扫描做。测试/影子实例禁写信箱。 ### 5.3 事务边界 | 动作 | 显式事务 | 持 `PIPELINE_LOCK` | 触及航班表 / 事件 | 原子性来源 | |---|---|---|---|---| | 收报入队(`insertIfAbsent`) | 是 | 否 | 否 | 同库事务 | | 身份首次绑定 | 否 | 否 | 否 | 单语句 + 唯一约束 | | 业务型领域变更(航班变更 + 待发事件) | 是 | 是 | 是 | 同库事务(`INV-3`) | | Redis 航班快照写 | 否 | 是(处理步骤锁跨越本步) | 否 | 外部副作用,不在 PG 事务内;写成功是终态事务的前置(`INV-10`) | | 业务型终态(`SUCCEEDED` + 回填意图) | 是 | 是 | 否 | 同库事务(`INV-3`) | | 非业务型终态(`MALFORMED` / `PROTOCOL` / `SKIPPED` / `EXHAUSTED`) | 否 | 否 | 否 | 单语句(终态与回填意图同一条 UPDATE) | | 航班历史清理的物理删除 | 是 | 是(落实 `US-14` AC4) | 是 | 同库事务:复查判据 + 历史写入成功后删除 | | 回填(信箱标记 + `BACKFILL_AT`) | 否 | 否 | 否 | 跨库两次单写;幂等可重跑 | | 人工重放(批量改回 `PENDING`) | 否 | 否 | 否 | 单语句批量;`MessageLifecycleGate` 与回填互斥 | 航班变更与终态不在同一事务,中间夹 Redis 写(`INV-3`、`INV-10`)。`PIPELINE_LOCK` 跨 Redis 写,与历史清理互斥(`US-14` AC4);无第二写者时不额外串行。 ### 5.4 历史积压 积压走同一 FIFO 路径,无加速/旁路/跳队。退避与次数上限不变。跳过的行 `SKIPPED` 后走写回。完成时限不作承诺(`CLM-5`);指标见 [reference.md](reference.md)。 ## 6. 回填 ### 6.1 事实与扫描谓词 终态落库时记回填意图;写回由扫描驱动,跨库单写、幂等。扫描谓词: ```text STATE ∈ {SUCCEEDED, SKIPPED, DEAD} -- 终态 AND BACKFILL_AT IS NULL -- 标记尚未确认 AND BACKFILL_ABANDONED_AT IS NULL -- 未放弃(放弃行可人工恢复) AND ( BACKFILL_NEXT_AT IS NULL -- 异常兜底:终态行没有退避时间 OR BACKFILL_NEXT_AT ≤ NOW -- 退避到期 OR ENQUEUED_AT < NOW − R ) -- 进入强补写窗口,覆盖退避 ORDER BY BACKFILL_ATTEMPTS ASC, MSG_ID ASC -- 公平轮转,永久失败行不占满批次 LIMIT PARAM:msgx.pipeline.backfill-batch ``` 超期只看 `ENQUEUED_AT`,不用 `RECEIVED_AT`。信箱清理见 `C-1`。 ### 6.2 四种结果与放弃 | 结果 | 判定 | 处置 | |---|---|---| | 写入成功 | 标记为空、写入 1 行 | 记 `BACKFILL_AT`,不再重试 | | 早已有标记 | 写入 0 行且信箱行存在 | **视为成功**,不覆盖已有值,记 `BACKFILL_AT` | | 信箱行不存在 | 写入 0 行且行已删 | 立即放弃(`MISSING_ROW`)并告警 | | 暂时性故障超 `R` | 超时/连接失败到 `R` 仍未写回 | 停自动重试(`TRANSIENT_DEADLINE`)并告警;`R` 前只退避 | 放弃 ≠ 已写回:不写 `BACKFILL_AT`,信箱行不删(`C-1`)。 ### 6.3 `R` `R` 见 [reference.md](reference.md) `PARAM:msgx.pipeline.overdue-backfill`: - 超 `R` 未写回 → 每轮都试,不等退避。 - 暂时性故障到 `R` 仍失败 → 停自动重试;`backfill-max-attempts` 只告警。 - `MISSING_ROW` 立即放弃。`R ≤ R_keep`。写回已了结且超保留期(约 1 月,`C-1`)后删原文;放弃行不删。 ## 7. 日计划快照与请求匹配 ### 7.1 快照 `SCHD-DNLD`/`RESP` 共用 `ScheduleProcessor.applyScheduleRecords`: 1. 已成功 → 幂等,只追加留痕。 2. 整包校验失败 → `DEAD(PROTOCOL)`,不写半包(`INV-4`)。 3. 分批写:跨运营日整包失败;快照缺席航班标删、发删除事件、删 Redis(`INV-7`)。每批同事务写变更 + 事件(`INV-3`)。 4. 整包成功 → `SUCCEEDED` + 回填意图;留痕在事务外。 字段语义见「航班域」。`RESP` 须匹配开放请求,否则不更新(`G-RESP-GUARD`)。 ### 7.2 上游请求与静态数据 请求状态机(`G-REQ-TRACK`): ```text PENDING → SENT → DONE ├──→ EXPIRED └──→ FAILED(收到 EROR,US-09 AC3) ``` - 开放槽:`RQRD`/`RQFD` 各一条(`US-09` AC1);同类新请求前作旧请求过期。 - `COUTMSGS` 确认后才 `SENT`;本地未确认须补偿,不能盲重发。 - EROR → 标 `FAILED` 并告警(`US-09` AC3)。 - 应答按类型匹配开放请求(`US-09` AC2);时间用本地时钟。 - 参考应答写 `REF_MASTER`;日计划走快照。结案后迟到应答不改状态。 - 出站只保证写入信箱(`C-4`、`CLM-4`)。 ## 8. 事件投递 ### 8.1 `KAFKA:msg` 同 `FLID` 内按 `EVENT_ID` 保序;跨 `FLID` 不承诺顺序。消费端用 `(FLID, STATE_VERSION, UPDATED_AT)` 防旧盖新。 每批在读取时冻结 `EVENT_ID` 集合。`EVENT_ID` 全局串行分配,顺序 = 提交顺序(`US-14` AC4)。 确认发送后标 `SENT`;失败退避,用尽 → 死信。外部调用须有界超时。 至少一次投递(`D2`);配置见 [reference.md](reference.md)「信箱与外部依赖」。 ### 8.2 `KAFKA:schd` 按 `FLID` 单行 upsert,只保留最新 `STATE_VERSION`。每次更新换 `EVENT_ID`(写代次)。 - **只进不退**:`STATE_VERSION` 只升不降。 - **条件标记**:`SENT` 时 `WHERE STATE_VERSION = 本批版本`;已被新版本覆盖则下轮重发。 发送:取未发送行(`PARAM:msgx.schd.flush-limit`)→ 整批 `SCHD.FLTR` JSON(`C-9`)→ 条件标 `SENT`。删航班只走 `msg`。 周期与批上限见 [reference.md](reference.md)。`msg` 与 `schd` 不承诺顺序。 ### 8.3 事件清理 已 `SENT` 行按 `PARAM:msgx.pipeline.event-retention` 清理。`msg` 死信须人工后再删;`schd` 死信在新代次出现时重置为 `PENDING`。 ## 9. 失败恢复与维护作业 ### 9.1 失败、重试与重放 `ProcFailure`/`FailureScheduler` 统一失败落账与退避。启动自检:退避档位数须比尝试上限少一。失败在具体消息/事件/批次处记数;外层不重复加次数。 `ReplayService` 白名单内可从 `FAILED`/`DEAD` 回 `PENDING`,重置次数与时间,**不改 `IDENTITY_KEY`**。与写回互斥(`MessageLifecycleGate`)。重放不恢复历史顺序(`CLM-3`)。 ### 9.2 中断恢复 恢复只看持久化记录。PG 备份回退可能重复发 Kafka/写回,接受至少一次,不重放业务。`SCHD_SNAP_LOG` 在事务外,崩溃可丢。 | 中断位置 | 重启后的判定 | 恢复动作 | |---|---|---| | 已写入信箱、未入队 | 信箱行处理时间为空且 PG 无记录 | 重扫补建处理记录 | | 事务执行中 | PG 无该消息终态 | 事务整体回滚,按 `PENDING` 重新处理 | | 领域事务已提交、Redis 写失败或终态未提交 | 该消息无终态(`PENDING`),仍占队头 | 整条消息重处理:Redis 航班快照按当前完整态重写;领域再跑是否只留一次效果见 `US-03`、`G-FLOP-IDEMPOTENT`;已提交结果不回滚(`US-03` AC3) | | 事务已提交、标记未写 | 终态行仍持有回填意图 | 仅补写标记;业务处理结果保持不变 | | 标记写入中途 | 标记仍为空 | 重新写入;重复写入同一值无副作用 | | 回填时信箱行已不存在 | 写入 0 行且信箱行不存在 | 立即放弃自动重试(`MISSING_ROW`)并告警;放弃不等于标记已确认,仍需人工对账 | | `RECEIVED_AT` 为 NULL | 超期分支以本地 `ENQUEUED_AT` 判定,不受库方时钟与 NULL 影响 | 按 `R` 超期强补写;未超期则按退避重试 | | 投递目标已接受、`SENT` 未置 | 事件仍 `PENDING` | 允许重发,消费方按事件身份去重 | | PG 从备份恢复 | 终态与事件回退到备份点 | 按至少一次接受重复;不重放业务、不据此改写航班 | ### 9.3 生命周期与清除 `JobRunner` 周期跑写回扫描、历史清理、留痕清理;不挡主泵 FIFO。历史清理跳过处理中的航班(`US-14` AC4)。 清除须终局证据(航班 `US-14`/`D1`;信箱 `C-1`)。证据不明 → 删 0 条。写回失败记录在信箱删前可查(`US-10` AC2)。 **逐对象**(保留期见 [reference.md](reference.md)) | 对象 | 终局判据 | 归档目标 | 清除证据 | 执行方 | 偏差 | |---|---|---|---|---|---| | 共享信箱 `CMINMSGS` 原文 | 回填了结(`BACKFILL_AT` 非空)且超保留期(约 1 个月,`C-1`) | — | 回填已了结 + 超保留期;放弃行无 `BACKFILL_AT`,不删 | 我们 | — | | `FLIGHT_SCHD` + 资源明细 | 判史规则 | 历史存储 | 历史写入确认 + 版本复查 | 我们 | — | | 航班历史存储 | 保留期 | — | — | 我们 | `G-FLIGHT-HIST-RETENTION` | | `SCHD_SNAP_LOG` | 保留期 | 无(本地可重建) | 无 | 我们 | — | | `MSG_EVENT` 已发送行 | `SENT` | 无 | 无 | 我们 | — | | `PROC_STATE` 终态行 | 见下 | 无(到期直接删除) | 回填了结 | 我们 | `G-PROC-CLEANUP` | | `REQ_TRACK` 关闭态行 | 保留期 | 无 | 无 | 我们 | `G-REQ-TRACK-RETENTION` | **`PROC_STATE` 清理**(`US-11`):终态 + `BACKFILL_AT` 非空 + 超保留期(从 `UPDATED_AT` 起)。删除按 `STATE` 条件执行,0 行则跳过(与人工重放互斥)。批量删除不持 `PIPELINE_LOCK`。 保留期从终局后起算,未写回不进候选。其余:历史清理先写 ES 再删(「航班域」);留痕按 `(SCOPE_END, RECV_AT)`;事件见「事件清理」。信箱见 `C-1`/`C-2`。 ## 10. 容量假设 单机场、单实例;日消息千~万级;单条 ≤ 10⁴ 字节;延迟秒级可接受。不引入多实例/分布式锁/分区表。参数依据见 [reference.md](reference.md)(`CLM-6`)。 ## 11. 航班域:数据模型与合并 PG 是航班数据源(`INV-5`);Redis 从 PG 同步,处理完成前写入(`INV-10`)。`FLID` 全局唯一。写入与对账只看 `FLIGHT_SCHD` 及明细;Redis 只读。 ### 11.1 数据模型 | 对象 | 职责 | |---|---| | `FLIGHT_SCHD` | 一行一个 `FLID`,保存标量字段、`STATE`、`STATE_VERSION`、`OPERATION_DAY`、最近消息 ID 和审计时间。 | | 资源明细表 | 保存登机门、值机柜台、转盘、计划机位、滑槽、延误、靠撤桥、轮挡等变长集合;`SRVT`/`VIPF` 专用明细见 `G-SRVT-VIPF`。主键为 `(FLID, ORDINAL)`。 | | `FLIGHT_ROUTE_POINT` | ROUT 与 ERUT 两类路线点,使用 `ROUTE_KIND` 区分;主键应包含该列,避免两类路线的序号冲突。 | | `PROC_STATE` | 信箱消息的处理终态、业务身份幂等记录,以及回填事实(`RECEIVED_AT` / `BACKFILL_*`)。 | | `MSG_EVENT` | 事务 outbox,承载整态快照、变更通知和删除事件(tombstone)。 | | `SCHD_SNAP_LOG` | 日计划处理留痕,只追加、可重建,不参与状态决策。 | ### 11.2 航班身份与运营日 `OPERATION_DAY` 从 `SODT` + 机场时区/切日规则推导,不是接收日。未收录可为 `NULL`。跨运营日冲突 → `DEAD(PROTOCOL)`,整包不写(`INV-4`)。 ### 11.3 字段与集合 三层:主表标量、集合明细、路线点。键名取 SIS 标签;语义见 [SIS 规范](legacy/SIS_AODB_RMS-V0.1.md) 与 [XSD](legacy/unisysaodbsis.xsd)。 **标量**(存于 `FLIGHT_SCHD` 主行,出现即覆盖;空串为显式清空) | 组 | 标签 | |---|---| | 身份与计划 | `ALCD`、`ALSC`、`FLNO`、`MVIN`、`SODT`、`FLTY`、`FLIN`、`ACFT`、`RENO` | | 班次与运营 | `TAOP`、`TAFL`、`TAID`、`TRML`、`CSOP`、`CSFT`、`MAID` | | 时间 | `ESTT`、`ACTT`、`BOTM`、`LACL`、`FINT`、`APPT`、`EGSR`、`EGST`、`PADT`、`NAAT`、`NEAT`、`PEDT`、`FTSS` | | 资源与状态 | `STND`、`PHAG`、`FHAG`、`MHAG`、`CNCL`、`REMC`、`MAXP`、`VIPP`、`VIPR`、`LBNO`、`LBWT`、`PAXC`、`EXSC`、`EXSR` | **集合**(存于明细表;报文带了该集合就按完整合并结果整体替换,元素顺序取报文顺序;未出现则保留本地值) | 集合 | 元素键(属性在前) | 条数上限 | 定义处 | |---|---|---|---| | `GTDT` | `GTNO`、`GATE`、`PGOT`、`PGCT`、`GOTM`、`GCTM`、`GTYP` | 99 | `SIS:3.34` | | `CKDT` | `CKNO`、`CHKC`、`CCLS`、`PCOT`、`PCCT`、`COTM`、`CCTM`、`CTYP` | 99 | `SIS:3.24` | | `CLDT` | `CLNO`、`BELT`、`BCLS`、`PCOT`、`PCCT`、`FBAG`、`LBAG`、`BTYP` | 99 | `SIS:3.25` | | `CHDT` | `CHNO`、`CHUT`、`CCLS`、`PCBT`、`PCET`、`CBTM`、`CETM`、`CTYP` | 99 | `SIS:3.26` | | `PSDT` | `PSNO`、`PSST`、`STST`、`STET` | 9 | `SIS:3.38` | | `CHOT` | `CSNO`、`CHTM`、`CHID`、`CHST` | 99 | `SIS:3.22` | | `DELY` | `CODE`、`STRT`、`DURA`、文本 | — | [XSD](legacy/unisysaodbsis.xsd)「FLOP 元素」 | | `ABTM` | `ASNO`、`ABDG`、`ABOP`、`AOTM` | 99 | [XSD](legacy/unisysaodbsis.xsd)「FLOP 元素」 | | `ROUT` / `ERUT` | `RTNO`、`APCD`、`SCAT`、`SCDT` | SIS 报文容量 6 / 7;本地各自最多保留 4 条(`US-05` AC3) | `SIS:3.40` | | `SRVT` | `OPER`、`SRTC`、`SRQT`、`SRST`、`SRET`、`SRPR`、`SANR`、`SARR` | 无界 | `G-SRVT-VIPF` | | `VIPF` | `OPER`、`VPCD`、`VFES`、`VIPT/OPER`、`VIPT/VSCD`、`VIPT/VTQY`、`VIPT/VTST`、`VIPT/VTET` | 无界 | `G-SRVT-VIPF` | `SRVT`/`VIPF` 只存原文,不参与合并。`MAFL` 由子航班派生(`G-MAFL`)。 - `ORDINAL` 是持久化顺序,从 1 开始;`SOURCE_SEQ` 是上游序号,允许为空或重复。 - 相同资源号不代表同一条分配,禁止按资源号去重。 - 每次持久化完整航班状态时,明细表按该 `FLID` 先删后插,以完整合并结果为准。 - ROUT 与 ERUT 是两类独立集合,不能因相同序号覆盖彼此。 - `CHDT` 的类字段固定为 `CCLS`/`CTYP`;当前 wire DTO 与持久化列误写成 `CHCLS`/`CHTYP`,见 `G-FLOP-UNMAPPED`。 - 主/共享:`MAID` 指向主航班 `FLID`;`MAFL` 从子航班派生,不入站。 ### 11.4 `MAFL` 主航班派生集合:`{FLID, FLNO}`(`US-06` AC2)。仅主航班(`MAID` 空)带 `MAFL`;共享航班不带。已删子航班自动退出。子航班变更须通知主航班(`msg`+`schd`)。同事务写入;`MAID` 须索引。 ## 12. 航班域:合并、删除与生命周期 ### 12.1 SCHD 整包校验通过后分批写入;快照缺席标删(`INV-7`)。未带字段清空(`C-6`)。成功航班推进 `STATE_VERSION` 并写 `schd`+`msg` 事件。重复由 `PROC_STATE` 控制;校验失败整包不写(`INV-4`)。 ### 12.2 动态运行事件(FLOP) 只改报文带的字段/集合(见「字段与集合」)。`STYP` 须命中白名单;未知 → `SKIPPED`(`US-03` AC2)。逐类规则见 `G-FLOP-IDEMPOTENT`。 **现行白名单 7 类**(`US-05` AC1):`ABTM`、`DELY`、`PSDT`、`CKDT`、`CLDT`、`CHDT`、`GTDT`。下表其余行是闭合目标(`Q3`),不是现行白名单。 | SIS | STYP | 目标 | 空标签 / 缺失语义 | |---|---|---|---| | XSD FLOP | `ABTM` | `ABTM` 集合 | 现行基线须处理(`US-05` AC1);形态与逐类终态待 `Q3` | | XSD FLOP | `DELY` | `DELY` 集合 | 现行基线须处理(`US-05` AC1);形态与逐类终态待 `Q3` | | `SIS:3.19` | `ACFT` | `ACFT` 标量 | 字段为 M,未写明空语义 | | `SIS:3.20` | `ACTT` | `ACTT` 标量 | 空 = 清除已有实际时间 | | `SIS:3.21` | `BOTM` | `BOTM` 标量;非空时设置登机状态 | 空 = 清除登机时间并重置登机状态 | | `SIS:3.22` | `CHOT` | `CHOT` 集合 | 集合按完整结果替换;元素内 `CHTM` 空 = 删除该轮挡时间 | | `SIS:3.23` | `FLTY` | `FLTY` 标量 | 字段为 M,未写明空语义 | | `SIS:3.24` | `CKDT` | `CKDT` 集合 | 空 `` = 现无柜台分配;AODB 实际会发,照常接收处理(`US-05` AC3) | | `SIS:3.25` | `CLDT` | `CLDT` 集合 | 空 `` = 现无转盘分配;AODB 实际会发,照常接收处理(`US-05` AC3) | | `SIS:3.26` | `CHDT` | `CHDT` 集合 | 空 `` = 现无滑槽分配;AODB 实际会发,照常接收处理(`US-05` AC3) | | `SIS:3.27` | `CNCL` | `CNCL` 标量 | 空 = **撤销**上一次取消(不是清空时间) | | `SIS:3.28` | `ESTT` | `ESTT` 标量 | 空 = 删除预计时间 | | `SIS:3.29` | `FDEL` | 走删除路径(「删除与重建」) | 恒为空标签 | | `SIS:3.30` | `FDIV` | `FDIV`(`DDES`/`DDIR`),当前未映射(`G-FLOP-UNMAPPED`) | 空 `DDES=""` = 清除转场标志 | | `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` 集合 | 空 `` = 现无登机门分配;`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` 集合 | 空 `` = 现无机位分配;AODB 实际会发,照常接收处理(`US-05` AC3) | | `SIS:3.39` | `RENO` | `RENO` 标量 | 空 = 清除注册号 | | `SIS:3.40` | `ROUT` | `ROUT` 集合 | `SCAT`/`SCDT` 分别对起点/终点缺席。SIS 报文容量 6/7;本地 `ROUT`/`ERUT` **各自最多保留 4 条**(`US-05` AC3),不保存 `SCAT`/`SCDT` | | `SIS:3.41` | `TAOP` | `TAOP`/`TAFL`/`TAID` 标量 | 任一为空 = 该到达航班的经停连接断开 | | `SIS:3.42` | `TRML` | `TRML` 标量 | 空 = 删除航站楼 | | `SIS:3.43` | `VIPP` | `VIPP`/`VIPR` 标量 | 空 = 删除;SIS 另要求 RMS 忽略 `VIPP`(忽略事件还是忽略字段,SIS 未写明,须以真实报文确认,见 `G-FLOP-SEMANTICS`) | **legacy 有、SIS 无**:`PADT`、`FTSS`、`STND`、`BDPB`、`REMC`(形态待 `Q3`)。**SIS 有、legacy 无**:`CHDT`、`FINT`、`MAXP`。**未映射**:`G-FLOP-UNMAPPED`。不改 `OPERATION_DAY`;目标航班缺失时的终态待 `Q3`。实现偏差见 `G-FLOP-SEMANTICS`。 ### 12.3 删除与重建 FDEL:`ACTIVE→DELETED`,写 tombstone。物理删除仅历史清理成功后(`US-14`、`D1`)。快照缺席也标删(`INV-7`)。 ADFT:Set-only(`US-04` AC2),未带字段不清。有 `SODT` 则算 `OPERATION_DAY`。 主/共享:删共享 → 重算主航班 `MAFL` 并通知;删主 → 级联删子并通知。须原子,按 `FLID` 值比较。 ### 12.4 Kafka 与读取 `schd` = 整态快照;`msg` = 变更通知。不承诺 topic 间顺序。删航班只走 `msg`(`C-9`)。读航班须同事务/一致读边界批量加载。 ### 12.5 生命周期 运营日过去 ≠ 航班结束。历史清理:保留期 + 终态证据 → 先写 ES 再删;失败删 0 行(`D1`)。 ## 13. 静态参考数据 静态参考数据:类别、结构、合并语义。字段语义见 [SIS 规范](legacy/SIS_AODB_RMS-V0.1.md);验收见 `US-13`。 ### 13.1 来源 | 来源 | SIS 节 | 形态 | |---|---|---| | AODB 参考数据事件 | `SIS:3.1`~`SIS:3.13` | `META.TYPE` 即类别码;`STYP` ∈ `DNLD` / `RESP` / `ADD` / `UPD` / `DEL` | | AODB 资源状态事件 | `SIS:3.14` | `TYPE=RSTA`;`DNLD` 是单条状态更新,`RESP` 才可包含多条 | | AODB 应答参考数据请求 | `SIS:3.15` | 复用对应类别格式且 `STYP=RESP`;**没有请求 ID 或关联字段**,以响应 `TYPE` 匹配原请求 `STYP` | ### 13.2 类别 | `RTYPE` | 含义 | 唯一键 `RKEY` | SIS 节 | |---|---|---|---| | `COUL` | 国家代码 | `COUC` | `SIS:3.1` | | `ARPT` | 机场代码 | `ITCD` | `SIS:3.2` | | `AIRL` | 航空公司代码 | `ITOP` | `SIS:3.3` | | `AIRC` | 机型代码 | `ITAT` | `SIS:3.4` | | `REGN` | 注册号 | `RNUM` | `SIS:3.5` | | `ORGN` | 机构代码 | `OGID` | `SIS:3.6` | | `FLTL` | 航班类型代码 | `FTYP` | `SIS:3.7` | | `TLST` | 航站楼代码 | `TCOD` | `SIS:3.8` | | `GLST` | 登机门代码 | `GCOD` | `SIS:3.9` | | `SLST` | 机位代码 | `SCOD` | `SIS:3.10` | | `CLST` | 值机柜台代码 | `CCOD` | `SIS:3.11` | | `BLST` | 行李转盘代码 | `BCOD` | `SIS:3.12` | | `CHLT` | 行李滑槽代码 | `CCOD` | `SIS:3.13` | | `RSTA` | 资源状态 | (`RTYP`, `RSID`) | `SIS:3.14` | `CLST` 与 `CHLT` 复用同名标签 `CCOD`、`CNMC`、`CTML`、`CCAT`,语义不同,只能靠 `RTYPE` 区分。 ### 13.3 结构与合并语义 逻辑视图 `REF_MASTER`,键 `(RTYPE, RKEY)`;`RSTA` 加 `RTYP`/`RSID`。物理为独立表组。 - 13 类:`DNLD`/`RESP` 全量替换(同 `RTYPE`);`ADD`/`UPD`/`DEL` 单条增量。 - `RSTA`:单条覆盖或 RESP 多条;不以「包内未出现」删其他状态。 - 删除只认 `STYP=DEL`;空标签 = 不可用,不是删(与航班动态相反)。 - 应答 `STYP=RESP`,按 `TYPE` 配对 `RQRD.STYP`。 - 不进 `MSG_EVENT`,不参与航班推进。 SIS 声明的上游忽略与截断口径见 `SIS:3.1`、`SIS:3.2`、`SIS:3.4`、`SIS:3.5`、`SIS:3.6`、`SIS:3.7`、`SIS:3.8`、`SIS:3.10`、`SIS:3.11`、`SIS:3.12`。未确认本地用途前不入模型;`US-13` 增补须说明用途。 ### 13.4 资源状态 `RSTA`:`RTYP` ∈ `BELT`/`CNTR`/`GATE`/`STND`;`STAT` = `E`/`D`。默认可用;禁用可带时间窗,到期自动恢复;无结束时间 = 一直禁用至新事件。 ### 13.5 admin-api 下游读取边界 SIS → 本网关 → PG → admin-api(`C-10`)。本网关不调用 admin-api。Oracle 待 `Q14` 验证。MySQL 只是信箱。