Files
msgexchange-v2/docs/decision-flight-state.md
T
windyboy ff6cec08c8 refactor(flight-schd): 按现场 11g 约束将运营航班存储改为宽表 (ACM2-28 修订)
现场环境仅提供 Oracle 11g(无任何 JSON 能力),废除 FLTR_JSON JSONB 整文档存储:

- V1.1.0 迁移重写:FLIGHT_SCHD 改为一行一航班宽表(SCHD.FLTR 标量字段列 +
  1:N 明细集合序列化文本列),SCHD_GEN.FLIDS_JSON 展开为 SCHD_GEN_FLID(FDAY, FLID);
  已应用过旧版迁移的环境需重建 schema 重放
- 契约层:FlightChange/Handler 在线视图改为字段集映射(与 legacy flightInfo
  hash 同构),仓储白名单拒绝未知字段;增量写=字段级合并(hmset 同语义),
  快照=整体替换
- 事件载荷:快照投递与投影重建经 FlightFieldsJson 确定性序列化(键序稳定)
- 影子对拍:FlightStoreDiffTool 改为 PG 宽表列值 vs legacy FLTR JSON 逐字段
  归一化比对,新增嵌套集合比对用例
- 测试:61 用例全绿(不变量门槛 1/2/3、UTC 方言、真实 PG 方言集成、清场五场景)
- 文档:decision-flight-state.md 追加 §8 修订记录(不改写定案历史),design.md 表说明同步

11g 方言移植(ON CONFLICT→MERGE、advisory lock 替代、Flyway/驱动矩阵)、
集合列升子表、类型化列提升等未尽事项另立 Plane issue 跟踪。
2026-09-07 17:04:57 +08:00

9.9 KiB
Raw Blame History

决策:运营航班表 FLIGHT_SCHD 落自有 PostgreSQL 作阶段 A 权威(已定案 · 采纳选项 C)

状态:已定案(讨论 issueACM2-28,采纳选项 C;关联修订 ACM2-12)。 本文正式确立选项 C 为最终方案:运营航班权威 FLIGHT_SCHD 与代版本 SCHD_GEN 提前至阶段 A 落自有 PostgreSQL;Redis 彻底退出动态权威与写路径。 交叉引用:architecture.mddesign.mduser-stories.md、ACM2-10FS1FS8 实施批次)。

1. 问题

阶段 A 航班动态权威 = Redis(flightInfo hash + SCHD_GEN),永续驻留、不落任何关系表 ACM2-12)。FLIGHT_STATE 表原属阶段 BDecision.kt 注释即「阶段 B 落 FLIGHT_STATE 同事务」)。要回答的问题:是否把 FLIGHT_STATE 提前到阶段 A 落自有 PG,作为运营航班的 权威存储。

2. 触发重估的事实

# 事实 出处
F1 Redis 全损后,FLOP 报文按 KEEP 语义「航班不存在 → SUCCEEDED 不重试」持续终结——空态被当正常态,状态损坏持续到下一次完整 DNLD;且这些报文已回填 DATE_PROCESSEDReplayService 白名单(FAILED/DEAD)无法找回 US-05 AC3、design.md §1.1
F2 当前唯一恢复手段 = 等下一次 DNLD 或人工触发 RQFD(依赖 AODB 外部响应,超时 60s);无本地 durable 副本 US-08、design.md §3.4
F3 dev Valkey 虽配 AOFcompose.yaml --appendonly yes),生产 Redis 拓扑(持久化策略/副本)未定;Redis 持久化本就是尽力而为,不构成状态安全边界 compose.yaml、§8 部署姿态
F4 PG 已是处理管道硬依赖(PROC_STATE/MSG_EVENT),主泵本就停摆于 PG 不可用——航班状态放 PG 不新增 系统级 SPOF design.md §2
F5 U05(PG 本地事务边界)正在实装;此刻调整事务模型成本最低,切流后迁移要重开 I2/I5 与影子对拍口径 ACM2-10 U05
F6 U09gen Redis 内 CAS 协议重设计)存在的根因就是「权威在 Redis、终态在 PG」的跨存储窗口——ACMA-8 v4 原设计 gen 本在 DBACM2-12 迁 Redis 仅因 FLIGHT_STATE 缓做 design.md §3.4 已知缺口
F7 Handler 输入视图 hgetAllFlightInfo() 每报文全量读 hash,已是 U22–U24 已知缺口;PG 按 FLID 索引读可顺带收敛 design.md §9

3. 选项

A — 维持缓做 + 运维缓解(ACM2-12 现状)

冷启动空态自动触发 RQFD、生产 Redis 强制 AOF+副本部署要求、Runbook 记录重建流程。 局限:F1 的永久损坏窗口依旧存在,缓解只是缩短;恢复依赖外部系统可用性。

B — PG 镜像(write-behind 灾备副本,非权威)

主泵在 Redis 写成功后异步把变更镜像到 PG,仅供灾难重建。 局限:镜像滞后窗口内的 FLOP 效果同样丢失,恢复后仍需 DNLD 修正(与 A 等价的损伤面); 却要付出接近 C 的复杂度(表 + 双表示一致性哨兵 + 重建任务)。性价比最差,仅列出备选。

C — FLIGHT_STATE 落自有 PG,作为阶段 A 权威(推荐)

航班状态变更并入既有 PG 事务 2(与 MSG_EVENT 插入、PROC_STATE→SUCCEEDED 同事务 原子提交);Redis 退出动态权威写路径。

  • 跨存储双写窗口(I2 的 Redis 先写)整体消失;U09 从「Redis Lua 协议重设计」变为 「SQL 版本 CAS + 集成测试」,gen/SCHD_GEN 随 FLIGHT_STATE 回 PG(回到 ACMA-8 v4 形态)。
  • Redis 全损场景不再存在:PG 即状态,重启即恢复;F1 的损坏路径被根除。
  • Handler 输入改为按 FLID 索引读(F7);US-12 GET /all/flights 读 PG。
  • 影子对拍沿用 ACM2-12 既有口径(自有 PG 独立 schema 比对),不新增负担。
  • 阶段 B 不受影响:清场/判史改为 SQL 驱动,ES 仍是历史投影。
  • 性能:机场报文量级(秒级峰值)下单行 JSONB upsert 亚毫秒,且在既有事务内,无新增往返。

C 的代价(须如实计入):

  • 推翻 ACM2-12 阶段 A 存储口径,I2/I5 不变量重述,U29 不变量测试清单同步。
  • FlightStateRepository 从 day 粒度(replaceDay)重设计为 FLID 粒度 upsert + day 快照 replaceSnapshotFlow 的 Lua 差删改 SQLredis-flight-store 健康指示器调整。
  • Redis 在阶段 A 角色大幅缩小(仅剩 orms_stand 热点缓存可选),部署面与文档需收口。
  • 与 U05/U09/U15 排序重排:先定此决策,再收 U05 事务边界。

4. 对比

维度 A 缓做+缓解 B 镜像 C PG 权威
Redis 全损后果 状态永久损坏至下次 DNLD 损坏窗口缩短,仍需 DNLD 修正 不存在该场景
事务模型 跨存储双写(I2/U09 复杂度保留) 双写 + 镜像一致性 单库原子(U09 消解为 SQL
新增范围 表+哨兵+重建 表+接口+事务改造(并入 U05/U09 批次)
影子对拍 不变 需比对三方 不变(口径已是 PG schema 比对)
恢复 RTO/RPO 依赖 AODB 响应 本地副本+DNLD 修正 重启即恢复,RPO=0

5. 建议

推荐 C。核心理由:F1 的损坏是永久且不可自动找回的(报文已回填、不可重放), 选项 A/B 只能缩短窗口不能根除;而 C 的增量成本大部分落在 U05/U09 本就要动的事务边界上, 时机(F5)与代价重合。若评审认为生产 Redis 必然配强持久化+副本且接受 DNLD 重建窗口, A 是最小代价回退位;B 不建议。

6. 定案结论(ACM2-28 决策记录)

# 问题 定案结论
Q1 生产 Redis 拓扑 / RPO 不再阻塞。Redis 退出权威与写路径,不构成状态安全边界。
Q2 表形态 表名定案 FLIGHT_SCHD。FLID 主键 + FLTR JSONB 全量 + FDAY 所属代列(可空)。派生字段后置。
Q3 U09 重定义 「Redis Lua 协议重设计」取消,改为「SCHD_GEN SQL 版本 CAS + Testcontainers PG 集成测试」。
Q4 Redis 去留 阶段 A 动态写路径归零;orms_stand 缓存不保留;US-12 读 PGredis-flight-store 健康指示器移除。
Q5 不变量重述 I2(变更+事件+SUCCEEDED 单事务提交);I4(覆盖+差删+版本推进单事务);I5(单写者主泵线程,PG advisory lock 保护)。
Q6 影子对拍口径 nextgen PG FLIGHT_SCHD vs legacy Redis flightInfo 跨存储 AST 递归比对(FS7 工具)。

7. 落地完成清单(FS1–FS8 全部交付)

  • FS1 迁移 V1.1.0__flight_schd.sql:创建 FLIGHT_SCHDSCHD_GENTIMESTAMPTZ 规范)。
  • FS2 FlightSchdRepository 接口与实装:快照批量写入、增量更新(ON CONFLICT 保留 FDAY)、域化差删、点查、SCHD_GEN SQL CAS、历史清场 deleteByFlids
  • FS3 MessageProcessor 事务 2 扩展:变更写入 + 事件写入 + SUCCEEDED 在单 PG 事务原子提交;Handler 视图按 FLID 点查。
  • FS4 SnapshotFlow SQL 化:单事务内批处理 upsert + 域内差删 + SQL CAS 推进 + 事件入队 + 终态标记;JobExecutor 清场删除闭环。
  • FS5 Redis 退役收口:删除 FlightRedisClient、Lua 脚本、FlightRedisHealthIndicatorREDIS_FLIGHT_INFO 投影与相关配置。
  • FS6 U29/U09 不变量测试门禁:崩溃幂等无自增、CAS 防并发、ADFT 存活保障、UTC 方言测试、ES 历史清场 5 场景全绿。
  • FS7 影子对拍 Diff 工具:FlightStoreDiffTool 递归 AST 字段归一化比较与已知合法偏离识别。
  • FS8 文档回改:架构、设计、用户故事与项目规范同步收敛。

8. 修订:11g 现场约束下废除 JSON 存储(本节追加,不改写上文定案历史)

触发:现场环境只提供 Oracle 11g(无任何 JSON 能力——无 JSON_VALUE、无 IS JSON 约束、无 JSON 类型, JSON 支持自 12.1.0.2 才引入)。Q2 定案的「FLTR JSONB 全量」存储形态在该约束下不成立: 整文档存储丧失库端校验、字段级索引与直接 SQL 可查性,违背「运营航班可被 DBA/运营直接使用」的初衷。

修订结论

# 问题 修订结论
R1 表形态 废除 FLTR_JSON JSONB 整文档,改为一行一航班的宽表FLID 主键 + FDAY 代列 + SCHD.FLTR 标量字段列(锚定 unisysaodbsis.xsd 契约与 legacy 派生字段 ABDG/LPSDT/ABN)+ 1:N 明细集合序列化文本列。字段即列,天然可索引、可直查。
R2 集合字段 登机口/柜台/转盘/桥/延误等 1:N 明细(单航班可达 99 条)暂存序列化文本列(*_TXT11g 移植为 CLOB);阶段 2/3 Handler 钉死语义后按需升独立子表。
R3 值语义 全部字段保持 legacy 字符串原样(不做库端类型转换),保证影子对拍逐字段保真;范围查询需要的类型化列(如 SODT→DATE)按查询需求逐列后置提升。
R4 SCHD_GEN FLIDS_JSON 同步废除,展开为 SCHD_GEN_FLID(FDAY, FLID) 行;版本 CAS 语义不变。
R5 值机视图 Handler 在线视图契约由 flid → FLTR_JSON 改为 flid → 字段集(与 legacy hgetAllFlightInfo hash 同构);增量写语义=字段级合并(与 legacy hmset 一致),快照=整体替换。
R6 对拍口径 FS7 Diff 工具改为 PG 宽表列值 vs legacy FLTR JSON 的逐字段归一化比对(数值精度/空值等价规则保留),比原 JSONB AST 比对更精确到字段。

未尽事项(11g 方言移植不在本修订范围,另行决策):存储模型已 11g 兼容,但仓储层仍存 PG 方言 (ON CONFLICT upsert 需改 MERGE)、I5 advisory lock 的 11g 替代(DBMS_LOCK)、Flyway/驱动 对 11.2 的支持矩阵。若「自有 PG → 现场 11g」成为确定部署形态,需按 ACM2-28 体例开独立决策记录 重开「自有库」平台定案,评估点在方言与并发原语,不在本修订已解决的存储形态。