# 架构 ## 1. 系统定位与范围 msgexchange-v2 是机场 OMMS 的上游报文处理中间件,用于替换旧版 `msgexchange-api`。 它读取 CIIMS、AODB 等系统写入共享 MySQL 信箱的 XML 报文,按顺序更新航班动态与静态参考数据,再将结果提供给下游。静态参考数据由 SIS 消息获得,是本版本的主要新增能力之一。 本系统负责**收报、解析、状态更新和结果投递**,不生成上游业务报文;admin-api 是处理结果的下游数据库读取方,本网关不调用 admin-api。其余非目标见 [requirements.md](requirements.md)「范围与非目标」。 - **主要入口**:轮询共享 MySQL 的 `CMINMSGS`。 - **兼容入口**:`POST /cminmsgs/send`,供现役兼容、手工工具和对拍使用;写入信箱后返回记录 ID,不是生产收报主路径。 - **输出**:Kafka 的 `msg` / `schd` 消息、共享 MySQL 的 `COUTMSGS` 出站信箱、供 admin-api 只读的业务数据库结果,以及查询 HTTP 接口;不直接推送前端。 - **当前范围(阶段 A)**:航班当前态落自有 PostgreSQL(`FLIGHT_SCHD` + 资源明细表 + `FLIGHT_ROUTE_POINT`,权威口径见 [implementation.md](implementation.md)「航班域」)。无 Redis 依赖;ES 历史投影属阶段 B。 现场供库时目标为 Oracle 11g,否则自建 PostgreSQL;Oracle 适配必须通过方言与集成验证后才能作为运行时选项。 本文只描述架构约束与归属,不代表能力已实现:机制见 [implementation.md](implementation.md),前提、不变量与可声明性见 [specification.md](specification.md),对外契约见同文件「契约」,需求见 [requirements.md](requirements.md),参数与代码入口见 [reference.md](reference.md);操作步骤在上线/切流前另立规程(设计阶段只保留前置条件与红线)。历史报文契约以 [SIS 接口规范](legacy/SIS_AODB_RMS-V0.1.md) 和 [XSD](legacy/unisysaodbsis.xsd) 为兼容依据。 ## 2. 总体架构 ```text CIIMS / AODB 等上游 │ 写入 XML ▼ 共享 MySQL:CMINMSGS │ 轮询未处理记录 ▼ ┌──────────────── msgexchange-v2(单实例)────────────────┐ │ ingress:发现报文 → PostgreSQL 持久化入队 │ │ │ │ │ processing:取 FIFO 队头 → 解析 / 去重 → 处理器决策 │ │ └─ PG 单事务:领域变更 + 终态 + 待发事件│ │ │ │ jobs:独立维护线程(回填补偿 / 历史归档 / 留痕清理) │ │ delivery:读取 PG 待发事件 → 投递 / 重试 │ └─────────────────────────┬──────────────────────────────┘ ├─ Kafka:msg / schd ├─ 共享 MySQL:COUTMSGS └─ 业务数据库 ──只读──▶ admin-api 处理结果提交后,再回填 CMINMSGS 的处理标记;失败需补偿。 查询接口与 admin-api 读取处理后的业务数据,不参与状态写入,也不向本网关提供参考数据。 ``` 收报、处理、投递与维护作业各使用独立线程,不占用 HTTP 事件循环。**航班当前态的写入只发生在持有 `PIPELINE_LOCK` 的事务内**,由主泵串行驱动。 技术栈:Kotlin + JDK 25、Micronaut 编译期依赖注入、JDBC 持久化;数据库变更由 Flyway 管理,只作用于自有 PostgreSQL。依赖版本以 `build.gradle.kts` 为准,不在本文重复维护。 ## 3. 模块职责 | 模块 | 职责与边界 | |---|---| | `ingress` | 轮询信箱、持久化入队及兼容 HTTP 写入;不解析业务报文。 | | `codec` | XML 解码,区分非法报文与可修复的解码失败。 | | `processing` | FIFO 调度、业务身份绑定与去重、领域决策与落库(SCHD/FLOP/FDEL/ADFT/静态参考数据);决策、事务与回填的职责边界见 [implementation.md](implementation.md)「消息、身份与决策」与 `INV-17`。 | | `delivery` | 消费待发事件,负责按目标保序、`schd` 聚合、投递和失败重试。 | | `jobs` | 回填补偿扫描、航班历史清理与留痕保留期清理;独立 job 线程执行,不参与 FIFO(与主泵的互斥见 `INV-18`)。 | | `domain` / `config` | 领域状态、事件和决策模型,以及运行参数。 | | `infra` | 仓储(JDBC/stub)、外部适配器、重试、健康检查与日志;通过接口隔离基础设施。 | 代码入口清单见 [reference.md](reference.md)「模块与代码入口」。 ## 4. 主流程 `InboxPoller` 发现 → 自有 PG 入队(`INV-2`)→ 主泵按最小未完成 `MSG_ID` 取队头、解码并按业务身份去重 → 处理器在持 `PIPELINE_LOCK` 的同一事务内写航班变更、待发事件、处理终态与回填意图(`INV-17`)→ 提交后回填共享信箱处理标记 → `Dispatcher` 投递 `KAFKA:msg` 与 `KAFKA:schd`(至少一次,`INV-10`)。 机制细节各有归属:扫描谓词与水位、分派与事务边界、回填、保序与 `schd` 聚合见 [implementation.md](implementation.md)。 ## 5. 必须保持的约束 本节只列约束的**归属**;完整定义与验证映射见 [specification.md](specification.md),实现与演进不得违反: - 消息严格 FIFO:`INV-3`、`INV-4`、`INV-5`(发现完整性依赖 `PRE-2`/`PRE-3`)。 - 动态状态单写者与写者集合互斥:`D2`、`INV-18`。 - 身份去重:`INV-9`。 - 快照可恢复与运营日不可变:`INV-12`、`INV-13`。 - 航班当前态的物理清除只发生在历史归档之后:`D1`。 这些约束优先于吞吐量优化。单写者降低了并发复杂度,代价是队头阻塞和吞吐上限;如需并行化,必须先重新定义顺序与状态归属,不能只调整线程数。 ## 6. 数据归属与一致性 | 存储 | 承载内容 | 职责说明 | |---|---|---| | 自有 PostgreSQL | 单行锁 `PIPELINE_LOCK`、处理状态与回填事实 `PROC_STATE`、消费水位 `INBOX_CURSOR`、待发事件 `MSG_EVENT`、请求跟踪 `REQ_TRACK`、航班当前态 `FLIGHT_SCHD` + 资源明细表 + `FLIGHT_ROUTE_POINT`、静态参考数据有效视图(逻辑模型 `REF_MASTER`)、留痕 `SCHD_SNAP_LOG` | 本系统唯一业务数据库。消息处理、状态推进、处理终态、回填意图与待发事件在单事务内原子提交;本地事务只在此库。记录级定义见 [implementation.md](implementation.md)「持久化记录」。 | | 共享 MySQL | `CMINMSGS` 入站信箱、`COUTMSGS` 出站信箱 | 外部系统所有。本系统仅执行约定的信箱读写与处理标记回填,不建表、不迁移 schema、不写历史表;由库方按 `Q9` 执行的清除与历史归档见 [specification.md](specification.md)「契约」。 | **不使用跨库事务。** PG 事务只能保证「处理结果与待发事件一起提交」(`INV-17`),不能覆盖 MySQL 回填或 Kafka 发送等外部副作用。跨存储依靠幂等、重试和持久化补偿恢复;各中断位置的判定与恢复动作见 [implementation.md](implementation.md)「中断恢复」。 对外投递的承诺边界见 `C-29`;Kafka 生产者幂等不能消除应用重启或 outbox 重发带来的所有重复。 ## 7. 关键决策 仅保留仍具约束价值、且无法从正文与 [implementation.md](implementation.md) 直接推出的决策,按 `D1`–`D4` 连续编号;其余曾编号条目(严格 FIFO、stub 门控、本地事务、UNSUPPORTED 处理等)已在正文以约束形式表达,不再重复列表。第三列只给证据与偏差指针;可声明性见 [specification.md](specification.md),决策不因状态变化而撤销。 | 编号 | 决策及理由 | 证据 / 偏差 | |---|---|---| | D1 | 航班清场只在历史写入成功后进行,未接通时删 0 条;未经 FDEL 的清场须先补发删除事件。ES 历史投影(阶段 B)暂缓。 | 红线见 [implementation.md](implementation.md)「生命周期」 | | D2 | 动态状态单写者,生产只允许一个活动实例;多实例必须先具备可靠的排他保护。 | 事务行锁见 [implementation.md](implementation.md)「事务边界」;实例级排他属 `PRE-5`,可声明性见 `CLM-6` | | D3 | Kafka 生产必须同时满足确认级别、幂等生产与单连接在途上限三项约束;不允许通过关闭幂等来满足生产接入。 | 取值见 [reference.md](reference.md) 参数表 | | D4 | 自有库终态记录只归档到 `PROC_STATE_HST`,不侵入共享库的表结构或保留策略。 | `G-PROC-HST` |