refactor(storage): ACM2-12 落地——自有 PostgreSQL 全内部状态,共享 MySQL 仅信箱
按 ACM2-12 定案把仓库存储口径从"MySQL 六辅助表"推进到最终形态: - 迁移:删除 MySQL V2.0.0 六表脚本,新增自有 PG V1.0.0 (PROC_STATE/MSG_EVENT/PUMP_JOB/REQ_TRACK/REF_MASTER,PG 方言,REQ_TRACK.COUTMSGS_ID 按 U18 修为 BIGINT;FLIGHT_STATE 阶段 B 缓做不建表)。 - 配置:datasources.default = 自有 PostgreSQL(enabled=false 待 U05); 移除 datasources.reference/flyway.reference;新增 mailbox.shared-mysql(共享信箱, 仅 DML,不建表);test profile 显式启用 H2 内存 datasource。 - 接口/注释:Repositories KDoc 按 ACM2-12 归属(自有 PG / 信箱封装 / gen→Redis 占位 / FLIGHT_STATE 缓做);InboxService、Pump 事务模型注释对正 (信箱外部副作用 + PG 本地事务 + 回填最终一致)。 - 文档:architecture §1/§2/§3/§4/§5(D1/D2)/§6/§7/§8、design §1/§2/§3.1/§3.4/§3.5/§6/§9、 README 全部按 ACM2-12 收口(自有 PG + 共享信箱 + Redis 动态/gen + 阶段 B 缓做)。 验证:37 测试全绿;dev stub 冒烟仍可启动、/health UP、收报 200。 信箱适配层(CminmsgMailbox/OutboxMailbox)、gen→Redis Lua、作业窗口语义、影子重设计 属 ACM2-12 Checks ②③④⑤(U05/U09 批次)。
This commit is contained in:
+41
-25
@@ -3,6 +3,9 @@
|
||||
> 现行架构权威为 Plane `airport_chengdu_msgexchange_api` 工作区的 **ACM2-3(综合架构 v4)**;
|
||||
> 脚手架跟踪 **ACM2-4**,评审与实施计划(U01–U30)**ACM2-10**。本文是仓库内的架构速览,
|
||||
> 与代码同步维护;两者冲突时以 ACM2-3 为准并回改本文。
|
||||
> **存储边界与阶段 B 以 ACM2-11/ACM2-12 决策为准**(自有 PostgreSQL + 共享 MySQL 信箱 +
|
||||
> Redis 动态/gen;阶段 B 缓做)——ACM2-3 中"同库事务锚 / MySQL 六辅助表 / 阶段 B"表述
|
||||
> 已被上述决策修订。
|
||||
> 配套设计细节见 [design.md](design.md)。
|
||||
|
||||
## 1. 系统定位
|
||||
@@ -14,9 +17,12 @@
|
||||
影子对拍(同入口双收,比对输出)→ 切流(nextgen 权威)→ 旧仓库冻结
|
||||
```
|
||||
|
||||
- legacy 维护不受本仓库影响;本仓库不声明 legacy 旧表 schema(见 §6 数据边界)。
|
||||
- legacy 维护不受本仓库影响;本仓库不声明 legacy 旧表 schema,**且不在共享 MySQL 建任何表**
|
||||
(CMINMSGS/COUTMSGS 所在库属他人系统,本系统仅信箱 DML——ACM2-12,见 §6)。
|
||||
- wire 契约冻结:消息结构唯一事实源为 `SIS_AODB_RMS-V0.1.md` + `doc/unisysaodbsis.xsd`;
|
||||
HTTP 端点路径与响应语义沿用现役(如 `POST /cminmsgs/send` 返回记录 ID)。
|
||||
- **影子对拍口径(ACM2-12)**:共享库是单信箱无法"同入口双收",影子输入改以共享库只读
|
||||
水位/回放 + 自有 PG 独立 schema 比对(详见 §8 与 ACM2-12 Checks ⑤)。
|
||||
|
||||
## 2. 技术栈
|
||||
|
||||
@@ -24,10 +30,10 @@
|
||||
|---|---|---|
|
||||
| 语言/运行时 | Kotlin 2.3 + JDK 25 | JDK 21 不可行(Micronaut 5.1 系要求 JVM 25+,ACMA-9 实测) |
|
||||
| 框架 | Micronaut 5.1.3 | 编译期 DI:KSP(`kotlin-ksp` + `micronaut-inject-kotlin`)生成 `*$Definition` |
|
||||
| 持久化 | 业务库:MySQL + Flyway;静态参考库:**PostgreSQL**(ACM2-11) | 仓储现为接口(Micronaut Data JDBC 实装属 U05,阶段 1 后续;`datasources.reference` enabled=false 待阶段 6) |
|
||||
| 权威存储 | Redis(阶段 A) | flightInfo hash;仅主泵线程写(I5);Lua 脚本原子覆盖 |
|
||||
| 持久化 | **自有 PostgreSQL**(全部内部状态)+ 共享 MySQL 信箱 | 自有库:消息管道 PROC_STATE/MSG_EVENT + PUMP_JOB/REQ_TRACK + 21 类 REF_MASTER(迁移 `db/migration`);共享库仅 CMINMSGS/COUTMSGS DML。Micronaut Data JDBC 实装属 U05(ACM2-12) |
|
||||
| 权威存储 | Redis(航班动态 flightInfo + 快照 gen) | 仅主泵线程写(I5);Lua 原子覆盖/版本推进(gen 协议重设计属 U09) |
|
||||
| 投递 | Kafka(acks=all + 幂等) | outbox 模式,经 MSG_EVENT 表中转 |
|
||||
| 投影(阶段 B) | Elasticsearch + Redis 投影 + FLIGHT_STATE | 仅阶段 B 启用(`msgx.phase`) |
|
||||
| 投影(阶段 B) | Elasticsearch(历史) | **阶段 B 缓做(ACM2-12)**:FLIGHT_STATE 不落表,Redis 永续动态权威;历史投影链路不变 |
|
||||
| 注册中心 | Eureka(Micronaut 原生键) | 服务名契约 `msgexchangeapi`(影子 `msgexchangeapi-shadow`)——**U17 未落地**:当前注册名仍取 `micronaut.application.name`(=msgexchange-nextgen),`msgx.service-name` 无运行时消费方(见 §8 与 design.md §9) |
|
||||
| 可观测 | logstash TCP(Async 包装)+ MDC traceId + 自定义健康指示器 | 见 [design.md §8](design.md) |
|
||||
|
||||
@@ -73,15 +79,20 @@
|
||||
- **统一 FIFO(决策 1)**:定时作业(cron → PUMP_JOB 入队)与消息同队列,
|
||||
作业产物不绕过队头顺序;job 与队头的先后目前为入队时间近似,
|
||||
统一序号列属 U15(未实装,见 design.md §9 缺口清单)。
|
||||
**ACM2-12 修订**:PUMP_JOB 在自有 PG,作业不插队、仅在消息队头空闲/退避窗口由主泵执行。
|
||||
- **存储边界(ACM2-12)**:本框图内事务库为**自有 PostgreSQL**(PROC_STATE/MSG_EVENT/
|
||||
PUMP_JOB/REQ_TRACK/21 类);CMINMSGS/COUTMSGS 在**共享 MySQL 信箱**(外部副作用,非本系统
|
||||
表);Redis 除 flightInfo 还承载快照 gen。图中"事务 1/2"与 ACM2-3 的"同库事务"语义不同,
|
||||
见 §6:本地事务只在自有 PG,信箱交互为外部写+最终一致。
|
||||
|
||||
## 4. 模块职责
|
||||
|
||||
| 包 | 职责 | 对应 ACMA-8 | 主要类 |
|
||||
|---|---|---|---|
|
||||
| `ingress/` | 收报事务1:原文落库 + 伴生 PENDING 行;不解析报文 | 流程 1,I3 | `InboxController` `InboxService` |
|
||||
| `processing/` | 主泵:FIFO 领取、解码、identity 绑定、纯函数决策、事务2 | 流程 2/4,I1/I2/I5 | `Pump` `MessageProcessor` `SnapshotFlow` `Identity` `Handler(Registry)` |
|
||||
| `ingress/` | 收报:共享信箱写原文 + 自有 PG 建 PENDING(跨库外部副作用,ACM2-12);不解析报文 | 流程 1,I3 | `InboxController` `InboxService` |
|
||||
| `processing/` | 主泵:FIFO 领取、解码、identity 绑定、纯函数决策、自有 PG 事务2 | 流程 2/4,I1/I2/I5 | `Pump` `MessageProcessor` `SnapshotFlow` `Identity` `Handler(Registry)` |
|
||||
| `delivery/` | 投递:每 target 严格 FIFO、schd 聚合 | 流程 3 | `Dispatcher` `SchdAggregation` |
|
||||
| `jobs/` | 泵作业:清场/归档/投影重建(经 PUMP_JOB 同队列) | 流程 4/5/7,I4 | `JobExecutor` `HistorySweepJob` `ArchiveJob` `ProjectionRebuildJob` |
|
||||
| `jobs/` | 泵作业:清场/归档/投影重建(PUMP_JOB 自有 PG,作业窗口执行) | 流程 4/5/7,I4 | `JobExecutor` `HistorySweepJob` `ArchiveJob` `ProjectionRebuildJob` |
|
||||
| `codec/` | XML 解码 + 失败分类(MALFORMED vs CODEC_ERROR) | 决策 4 前置 | `XmlCodec` `DecodeResult` |
|
||||
| `domain/` | 状态机枚举、事件/决策模型、Phase 开关 | I1–I5 | `ProcState` `MsgEvent` `Decision` `MsgKind` |
|
||||
| `infra/` | 仓储接口、重试策略、Redis Lua、stub、健康、日志 | 数据模型节 | 见 design.md |
|
||||
@@ -91,8 +102,8 @@
|
||||
|
||||
| # | 决策 | 落点 |
|
||||
|---|---|---|
|
||||
| D1 | 作业与消息同队列(cron 只经 PUMP_JOB 入队,产物不绕过队头) | `Pump.tick` / `JobExecutor` |
|
||||
| D2 | 阶段 B:ES 投递成功后同线程**同步** enqueue 删除事件(不轮询 ack) | `Dispatcher.tick`(定案 2) |
|
||||
| D1 | 作业与消息同队列(cron 只经 PUMP_JOB 入队,产物不绕过队头)——**ACM2-12 修订**:PUMP_JOB 迁自有 PG 后不插队,仅队头空闲/退避窗口执行 | `Pump.tick` / `JobExecutor` |
|
||||
| D2 | 阶段 B(缓做,ACM2-12):ES 投递成功后同线程同步 enqueue 删除事件(不轮询 ack) | `Dispatcher.tick`(定案 2;阶段 B 评估后启用) |
|
||||
| D3 | schd 唯一出口是 flushSchd 批量聚合(逐条循环显式排除 KAFKA_SCHD) | `Dispatcher.tick`(U06/N03) |
|
||||
| D4 | 未实装 ≠ 非法:无 handler / staging 未实装 → FAILED(UNSUPPORTED) 可重放,绝不写终态 | `MessageProcessor` `SnapshotFlow`(U10/N21) |
|
||||
| D5 | 失败迁移在持有具体 head/batch 的边界完成;loop 只作最后防线,不吞 InterruptedException/Error | `MessageProcessor` `Dispatcher`(U08) |
|
||||
@@ -100,26 +111,30 @@
|
||||
| D7 | stub 装配门禁:`msgx.stubs=true` 才装配内存实装;与 `autostart` 组合支撑 dev 冒烟 | `infra/stub`(U07/U01) |
|
||||
| D8 | 编译期 DI(KSP)+ 启动期冒烟测试锁定 BeanDefinition 生成 | `build.gradle.kts`(U01) |
|
||||
|
||||
## 6. 数据边界
|
||||
## 6. 数据边界(ACM2-12 最终口径)
|
||||
|
||||
- **本仓库 Flyway 只建六张辅助表**:`PROC_STATE` / `MSG_EVENT` / `REF_DATA` / `REQ_TRACK` /
|
||||
`PUMP_JOB` / `FLIGHT_STATE`(`V2.0.0__aux_tables.sql`)。
|
||||
- **21 类静态主数据 → 独立 PostgreSQL 参考库**(ACM2-11 定案;`datasources.reference` /
|
||||
`StaticRefRepository`):航空公司/航线/机位/登机桥等静态数据迁出 `REF_DATA`;
|
||||
**`REF_DATA` 仅留守 SCHD_GEN 行**(流程 4 gen CAS 与 SUCCEEDED 同事务,见 design.md §2 注);
|
||||
航班动态权威 Redis(阶段 A flightInfo)**不变**。参考库表结构/迁移/21 类同步实装属阶段 6。
|
||||
- `CMINMSGS` / `CMINMSGS_HST` / `COUTMSGS` 等 legacy 旧表归 legacy 仓库维护(冻结期),
|
||||
本仓库不重复声明;**全新空库需先建 legacy schema**,否则收报首句 SQL 报表不存在
|
||||
(README「数据库初始化」节)。
|
||||
- 回滚兼容关键:SUCCEEDED 时回填 `CMINMSGS.SUBSYSTEM_*` + `DATE_PROCESSED/STATUS`,
|
||||
旧系统可按自身语义无缝接管(Runbook 第 7 步)。
|
||||
- **自有 PostgreSQL(本系统唯一自有数据库)**:全部内部状态,本地事务只在此库成立。
|
||||
`db/migration/V1.0.0__own_pg_pipeline.sql`(PG 方言)建:`PROC_STATE`(取消息侧:处理
|
||||
状态/重试/毒丸)+ `MSG_EVENT`(发消息侧:outbox)+ `PUMP_JOB`(作业调度)+ `REQ_TRACK`
|
||||
(15 类请求)+ `REF_MASTER`(21 类静态,SOURCE 审计)。
|
||||
- **共享 MySQL(cdairport,他人系统库)——本系统不建任何表/schema,仅信箱 DML**:
|
||||
收报写 `CMINMSGS`(含处理完成回填 DATE_PROCESSED/STATUS)、出站写 `COUTMSGS`
|
||||
(他人系统读取发送)。与信箱的交互是**外部副作用**,非本系统事务的一部分:
|
||||
收报 = 信箱落信成功(返回 CMINMSGS_ID)→ 自有 PG 建 PENDING 入队;PG 建行失败以共享库
|
||||
`DATE_PROCESSED IS NULL` 重扫补建;回填 = 处理成功后异步/补偿,最终一致(ACM2-12 影响面)。
|
||||
- **Redis**:航班动态 flightInfo(阶段 A 权威,I5)+ 快照 **SCHD_GEN**(Lua 内原子
|
||||
「覆盖+按代差删+版本推进」,协议重设计属 U09)。
|
||||
- **阶段 B(FLIGHT_STATE):缓做,不落表**;ES 仍承载历史航班(判史/查询),
|
||||
相关投影/删除事件链待阶段 B 重评估后启用。
|
||||
- legacy 旧表 schema 归 legacy 仓库维护;CMINMSGS/CMINMSGS_HST/COUTMSGS 结构与保留策略
|
||||
由共享库方管理,本系统只按契约读写(权限边界需与库方确认)。
|
||||
|
||||
## 7. 两阶段权威与当前就绪度
|
||||
## 7. 权威(阶段 A Redis;阶段 B 缓做)与当前就绪度
|
||||
|
||||
| 阶段 | 权威 | 投递目标 | 状态 |
|
||||
|---|---|---|---|
|
||||
| A(`msgx.phase=A`) | Redis flightInfo | KAFKA:msg、KAFKA:schd | 管道骨架+重试闭环已实装;Redis Lua/实仓储属 U05/U09 |
|
||||
| B(`msgx.phase=B`) | FLIGHT_STATE + 投影 | + ES:flight_hts、REDIS:flightInfo | 未实施(阶段 2 后) |
|
||||
| A(`msgx.phase=A`) | Redis flightInfo(+ gen) | KAFKA:msg、KAFKA:schd | 管道骨架+重试闭环已实装;自有 PG 数据层/信箱适配层属 U05;gen→Redis 协议属 U09 |
|
||||
| B(`msgx.phase=B`) | —(缓做,ACM2-12) | ES 历史投影 | 不落表、不启用;Redis 永续动态权威,阶段 B 价值重评估后再定 |
|
||||
|
||||
**就绪度(2026-09-07 复核口径)**:可编译、37 测试全绿、**dev stub 进程级冒烟实测可端到端**
|
||||
(`./gradlew run` 无外部依赖启动 → 收报 200 → `/health` UP,修复记录见 README「进程级 dev 冒烟」);
|
||||
@@ -133,7 +148,8 @@ U13(投递毒丸补全)、U15(统一序号)。逐项状态见 ACM2-10「
|
||||
- **影子隔离(目标态;U17/U26 未落地,勿按现状引用)**:服务名(`msgexchangeapi-shadow`)+ 独立
|
||||
schema + Redis key 前缀 + 独立 topic 三层隔离;当前代码仅 `msgx.register-eureka=false` 生效——
|
||||
Kafka topic 写死字面量 `"msg"`/`"schd"`(Dispatcher)、`FlightRedisClient.eval` 无 key 前缀参数、
|
||||
服务名未接 `msgx.service-name`(§2)。
|
||||
服务名未接 `msgx.service-name`(§2)。影子数据库:自有 PG 开独立 schema/实例;共享信箱无法
|
||||
双写,影子输入=只读水位/回放口径(ACM2-12 Checks ⑤)。
|
||||
- **网络信任模型**:`/cminmsgs/send` 无鉴权(沿用现役内网信任姿态);eureka default-zone
|
||||
回退 `127.0.0.1:8761`;口令/端点全部环境变量外置(零入库)。安全节细化属 U28。
|
||||
- **管理端点**:Micronaut 5.1 下 `/env` 默认**禁用**、`/beans` 默认 enabled+sensitive;dev/影子经
|
||||
|
||||
Reference in New Issue
Block a user