Files
msgexchange-v2/docs/flight-state.md
T
windyboy 8c6bb83b62 docs: 同步信箱生命周期实现口径——§4 缺口收敛、水位空洞老化、回填事实并入 PROC_STATE
message-lifecycle.md:§4 两个崩溃窗口随"终态与回填意图同体同行"消除(不再是缺口,改为
说明剩余未闭环项是回填跨库单写期间的持续失败);§5.1 补空洞老化规则(自增回滚空位会使
水位永久停摆,超出最大提交时延即判永久并放行,只跳过空洞不越过已存在的行);§5.2 补判据
机制(不依赖独立待办表,R 覆盖退避);§3 表格改回填意图与"到期或已达 NOW − R"。
design.md:§2.1 表以 INBOX_CURSOR 取代 BACKFILL_TODO、PROC_STATE 责任补回填事实;
§3.1 收报改为按 ID 区间扫描且不以标记为谓词;§3.3 终态由处理器事务内落库、死信同样可
补写;§6.1 维护作业改为 BackfillService.sweep;§7 补 max-commit-delay/overdue-backfill/
backfill-batch 与 mailbox.processed-value;§8 验证表补"终态未回填不得阻断发现"与"意图随
事务回滚";§9 入口表更新;§10 缺口两则改写为现状与待确认项。
architecture.md:§4 主流程第 1/3/4 步与 §3 存储表同步(水位、回填意图、单事务范围)。
flight-state.md:§2 对象表同步。user-stories.md:US-01/US-09 当前基础与落点改为实现现状、
Q2 口径改为"老化阈值待库方书面承诺"。
2026-09-10 11:00:02 +08:00

8.3 KiB
Raw Blame History

运营航班状态设计

本文是航班状态的唯一现行设计规范。它定义权威数据、处理语义、生命周期和对外投递;其他文档只描述管道或产品验收,不重复定义航班状态规则。

1. 目标与边界

系统从共享 MySQL 信箱接收 SIS/AODB 报文,把结果合并到自有 PostgreSQL 中的航班当前态,再通过 outbox 投递 Kafka。共享信箱和 Kafka 都不是状态权威,也不在本地事务的提交范围内。

  • FLID 是航班实例的唯一标识;不得由航班号、日期或资源号推断身份。
  • FLIGHT_SCHD 及其明细表是唯一权威当前态;展示视图只读,不能作为写入或对账来源。
  • 单活动主泵按信箱 FIFO 推进。事务内 PIPELINE_LOCK 只串行化本地状态提交,不替代选主或消息认领。
  • 状态写入、outbox 事件、处理终态和回填待办在同一 PostgreSQL 事务中提交;回填与 Kafka 投递在提交后独立重试。

现场目标库为 Oracle 11g;当前已验证的实现基准是 PostgreSQL。Oracle 适配未完成前,不能把它视为可切换的运行时选项。

2. 权威模型

对象 职责
FLIGHT_SCHD 一行一个 FLID,保存标量字段、STATESTATE_VERSIONOPERATION_DAY、最近消息 ID 和审计时间。
8 张资源明细表 登机门、值机柜台、转盘、计划机位、滑槽、延误、靠撤桥、轮挡等变长集合;主键为 (FLID, ORDINAL)
FLIGHT_ROUTE_POINT ROUT 与 ERUT 两类路线点,使用 ROUTE_KIND 区分;主键应包含该列,避免两类路线的序号冲突。
PROC_STATE 信箱消息的处理终态、业务身份幂等记录,以及回填事实(RECEIVED_AT / BACKFILL_*)。
MSG_EVENT 事务 outbox,承载整态投影、变更通知和删除 tombstone。
INBOX_CURSOR 共享信箱消费水位(读取进度,与处理标记互不替代)。
SCHD_SNAP_LOG 日计划处理留痕,只追加、可重建,不参与状态决策。

2.1 航班身份与运营日

FLID 是主键。OPERATION_DAY 从 SCHD 记录的 SODT 按配置的机场时区和切日规则推导;它不是消息接收日或落库日。

一旦已写入非空 OPERATION_DAY,同一 FLID 不得改到另一个运营日。遇到冲突,整包日计划按协议错误拒绝,既有状态保持不变。尚未由日计划收录的航班可以为 NULL;这不表示该航班没有运营日,只表示当前模型无法为它确定归属日。

2.2 字段与集合

标量、异常对象前缀字段和 SRVT/VIPF/MAFL 文本字段存于主表。变长资源完整保存到明细表,保留输入顺序和协议源序号:

  • ORDINAL 是持久化顺序,从 1 开始;SOURCE_SEQ 是上游序号,允许为空或重复。
  • 相同资源号不代表同一条分配,禁止按资源号去重。
  • 每次持久化完整航班状态时,明细表按该 FLID 先删后插,以完整合并结果为准。
  • ROUT 与 ERUT 是两类独立集合,不能因相同序号覆盖彼此。

3. 合并与写入语义

处理器保持纯粹:它根据当前完整态和已解码报文得到下一完整态与待发事件,持久化由统一事务入口执行。

3.1 SCHD 日计划

SCHD DNLD/RESP 在整包校验通过后,逐条将报文携带的航班写入当前态。日计划只更新或创建其携带的 FLID不会因其他航班未出现在本次报文中而删除任何记录

日计划在重叠字段上可以覆盖当前动态值;未携带的字段按合并规则保留,显式清空才清除。每个成功写入的航班推进 STATE_VERSION,并在同一事务登记 KAFKA:schdKAFKA:msg 事件。

消息重放由 PROC_STATE 的消息 ID 与 identity_key 控制;已成功提交的消息不得再次写入或重复登记事件。整包校验失败或运营日冲突时,整包不落地。

DNLD、RESP 和 ADFT 均已有路由入口。RESP 的请求匹配闭环、出站请求与超时重发仍是待交付项;未注册处理器不能被视为已实现。

3.2 动态运行事件

FLOP 事件只修改它表达的字段或资源集合,其余航班状态保持不变。每个动态子类型的语义都必须有明确 Handler 规则和回归测试,不能只因已被路由就推定其业务语义完整。

动态事件保留既有 OPERATION_DAY,也不基于接收时间重新推导它。未知或已删除航班的具体处理遵从对应 Handler 的幂等规则。

3.3 删除与重建

FDEL 是业务删除入口:仅在 ACTIVE → DELETED 时推进版本、保留明细并与 tombstone 同事务登记;重复 FDEL 或不存在的航班按幂等成功处理。

物理删除仅由独立历史清理在归档成功后执行。日计划报文不是删除依据。若未经 FDEL 而由生命周期清理,清理前需要登记一次 tombstone;已经 FDEL 的记录不重复发出。

ADFT 的字段缺失语义尚待上游确认。在确认前采用保守的 Set-only 规则:出现字段可更新,缺失字段不清空;不得把它当成日计划或动态全量替换。新建 ADFT 若带可解析的 SODT,按同一运营日规则计算 OPERATION_DAY;否则保留为 NULL

主/共享航班级联:删除共享航班时更新主航班 MAFL 并向主航班通知;删除主航班时级联删除其子共享关联并发出删除通知;主/共享关系必须一次原子变更,不出现主已删、子残留的半状态。共享航班增量通常只更新并通知主航班,不直接发共享通知。这些语义同样约束 FDEL 之外的生命周期清理。

4. 处理事务与失败规则

所有状态处理遵循下列顺序:

  1. 主泵只处理 FIFO 队头,解码并绑定业务身份。
  2. 校验消息结构、声明数量、航班标识和运营日;协议错误标记 DEAD,不提交半包。
  3. 在一个事务中取得 PIPELINE_LOCK,读取当前完整态,计算下一状态,写主表和明细表,登记 outbox 和回填待办。
  4. 同一事务提交处理终态;任一步失败则整体回滚并按错误类别重试或终止。
  5. 提交后回填共享信箱并异步投递 outbox;后续失败不得把已提交的 SUCCEEDED 改回失败。

identity_key发送方|类型|子类型|序号 构成,用于业务重复检测。STATE_VERSION 是单航班的单调版本,供下游判定新旧;它不是日计划版本,也不表示运营日版本。

5. Kafka 与读取

KAFKA:schd 是按 FLID 的完整状态投影。Dispatcher 可以合并同一 FLID 尚未投递的中间版本,只发最新状态;消费端用 (FLID, STATE_VERSION, UPDATED_AT) 防止旧投影覆盖新状态。

KAFKA:msg 只通知变化,不承载权威状态;两个 topic 不承诺顺序。FDEL 和必要的生命周期清理使用 tombstone:键为 FLID,删除记录以 null 值投递,通知下游移除旧状态。

读取完整航班需要读取主表和全部明细。当前逐航班读取有多次查询,尚未保证跨表一致性快照;批量加载与明确的一致性读边界是后续优化项。

6. 生命周期与开放项

运营日过去不等于航班结束。历史清理须同时满足配置保留期与终态证据或足够静默期,先成功写入历史存储,后物理删除当前态;历史存储失败时必须删除零行。

以下事项仍需确认或交付:

  • Oracle 11g 的完整方言与集成验证;
  • RESP 请求—应答匹配和出站请求重发;
  • ADFT 缺失字段和 FLID 重用的上游语义;
  • 未归属 OPERATION_DAY 航班的终止与保留策略;
  • ROUT/ERUT 联合主键迁移;
  • 批量一致性读取,以及动态事件仅在事务内计算一次的收敛。

7. 不变量

  • 本地 PostgreSQL 当前态是唯一权威;信箱、Kafka、Redis 和展示视图不是权威。
  • 同一时刻只有一个主泵推进 FIFO 状态;状态、事件、终态和回填意图原子提交。
  • 每个航班每次成功状态写入单调推进 STATE_VERSION;重复消息不重复推进。
  • FLID 唯一,已确定的 OPERATION_DAY 不可改变。
  • 报文未携带的字段不会被隐式清空;集合按完整合并结果写入。
  • 缺席于某个日计划不构成删除理由;删除只由 FDEL 或受控历史清理触发。
  • 外部副作用失败可重试,不回滚已提交的本地业务结果。