2026-09-07 10:27:44 +08:00
|
|
|
|
# msgexchange-v2(机场上游报文处理中间件)
|
|
|
|
|
|
|
|
|
|
|
|
**系统角色**:消费 CIIMS/AODB 等上游经共享 MySQL 信箱(`CMINMSGS`)投递的 XML 报文,
|
|
|
|
|
|
解析处理后维护 Redis 航班动态并向 Kafka / 出站信箱投递——**中间件**,非报文源系统。
|
2026-09-06 16:13:50 +08:00
|
|
|
|
|
2026-09-07 08:21:11 +08:00
|
|
|
|
依据 **ACMA-8 v4 综合架构**(单写者严格 FIFO 管道)与 **ACMA-6 技术选型**
|
2026-09-07 10:27:44 +08:00
|
|
|
|
(Micronaut 5.1 + Kotlin 2.3)搭建;**存储边界与阶段 B 按 ACM2-11/ACM2-12 定案**
|
|
|
|
|
|
(自有 PostgreSQL 全内部状态 + 共享 MySQL 仅信箱 + Redis 动态/gen,阶段 B 缓做)。
|
|
|
|
|
|
本仓库独立于 legacy `msgexchange-api`(Java 8 / Spring Boot 1.5 / Maven)——
|
2026-09-07 08:21:11 +08:00
|
|
|
|
过渡期两套系统并存(影子对拍→切流→旧仓库冻结),legacy 维护不受本仓库影响。
|
2026-09-06 16:13:50 +08:00
|
|
|
|
|
2026-09-07 10:27:44 +08:00
|
|
|
|
> **JDK 口径实测修正**:Micronaut 5.1 系构件要求 **JVM 25+**(`./gradlew :dependencies` 实测
|
|
|
|
|
|
> core 系解析 **5.1.13**,platform BOM **5.1.3**,classpath 混用);计划原定 JDK 21 不可行;
|
|
|
|
|
|
> 工程已按 **JDK 25** 配置(ACMA-9 记录)。
|
|
|
|
|
|
|
|
|
|
|
|
## 系统边界
|
|
|
|
|
|
|
|
|
|
|
|
| 方向 | 机制 | 说明 |
|
|
|
|
|
|
|---|---|---|
|
|
|
|
|
|
| **入站(主路径)** | JDBC 轮询共享 `CMINMSGS` | 上游经 CIIMS 等**外部系统**写信箱;本系统 1s 轮询 `DATE_PROCESSED IS NULL` 发现新信 → 自有 PG 入队(`InboxPoller`,U05) |
|
|
|
|
|
|
| **入站(compat)** | HTTP `POST /cminmsgs/send` | 手工注入/影子对拍;写信箱 + PG 入队,**非**生产主拓扑 |
|
|
|
|
|
|
| **处理** | 主泵 FIFO 管道 | 解码 → identity → Handler 决策 → Redis 动态权威态 |
|
|
|
|
|
|
| **出站** | Kafka + `COUTMSGS` | 向下游推送 msg/schd;请求类报文写出站信箱 |
|
|
|
|
|
|
|
|
|
|
|
|
与 SIS / legacy 一致:本系统**不**替代 CIIMS 落信,**不**生成原始 AODB 业务报文。
|
2026-09-06 16:13:50 +08:00
|
|
|
|
|
|
|
|
|
|
## 包结构 → ACMA-8 架构映射
|
|
|
|
|
|
|
|
|
|
|
|
| 包 | 职责 | 对应 ACMA-8 |
|
|
|
|
|
|
|---|---|---|
|
2026-09-07 10:27:44 +08:00
|
|
|
|
| `ingress/` | Ingress & Inbox:JDBC 轮询共享信箱发现新信 → 自有 PG 入队(+ HTTP compat 写路径),不解析报文 | 流程 1,I3 |
|
2026-09-06 16:13:50 +08:00
|
|
|
|
| `processing/` | Processing 主泵:严格 FIFO 领取、identity 绑定、纯函数决策、事务2 | 流程 2/4,I1/I2/I5 |
|
|
|
|
|
|
| `delivery/` | Delivery & Projection:每 target 严格 FIFO 投递、schd 聚合 | 流程 3 |
|
|
|
|
|
|
| `reference/` | Reference & Query:21 类同步 + 15 类请求状态机 | 流程 6 |
|
|
|
|
|
|
| `jobs/` | 泵作业:ARCHIVE / HISTORY_SWEEP / PROJECTION_REBUILD | 流程 4/5/7,I4 |
|
|
|
|
|
|
| `codec/` | XML codec(阶段 1 先 vendor 复用 legacy POJO,见 ACMA-6 选型) | 决策 4 前置 |
|
|
|
|
|
|
| `domain/` | 领域模型:Decision、事件、状态机枚举、Phase 开关 | I1–I5 |
|
2026-09-07 10:27:44 +08:00
|
|
|
|
| `config/` | `PipelineProps` 参数表(ACMA-8 参数初值,`msgx.*`) | — |
|
|
|
|
|
|
| `infra/` | 仓储接口、Redis Lua 装载、stub、健康、重试策略 | 数据模型节 |
|
2026-09-06 16:13:50 +08:00
|
|
|
|
|
|
|
|
|
|
## 资源
|
|
|
|
|
|
|
2026-09-07 08:29:49 +08:00
|
|
|
|
- `docs/legacy/SIS_AODB_RMS-V0.1.md` + `docs/legacy/unisysaodbsis.xsd`:**消息结构唯一事实源**
|
|
|
|
|
|
(wire 契约冻结,自 legacy 仓库复制以自包含;codec 实装依据,ACM2-2/ACM2-3)。
|
2026-09-07 08:21:11 +08:00
|
|
|
|
- `db/migration/V1.0.0__own_pg_pipeline.sql`:**自有 PostgreSQL**(唯一自有库)表结构
|
|
|
|
|
|
(PROC_STATE / MSG_EVENT / PUMP_JOB / REQ_TRACK / REF_MASTER,PG 方言),ACM2-12 定案;
|
|
|
|
|
|
共享 MySQL(CMINMSGS/COUTMSGS)仅信箱 DML 不建表;快照 gen 与航班动态在 Redis。
|
|
|
|
|
|
- `lua/snapshot_replace.lua`:同一 hash 原子“覆盖新代 + 按代差删”(流程 4,I4/I5;
|
|
|
|
|
|
随 gen→Redis 协议(U09)扩展版本推进)。
|
2026-09-06 16:13:50 +08:00
|
|
|
|
- `lua/batch_delete.lua`:3:30 清场批量删除(仅 ES 写成功集,I4)。
|
2026-09-07 08:21:11 +08:00
|
|
|
|
- `application.yml`:口令全部环境变量外置(零入库);`datasources.default`=自有 PG(enabled=false
|
|
|
|
|
|
待 U05)、`mailbox.shared-mysql`=共享信箱;`msgx.phase` 权威口径(A 现役;B 缓做);
|
2026-09-06 16:13:50 +08:00
|
|
|
|
pipeline 参数 = ACMA-8 参数表初值。
|
|
|
|
|
|
|
|
|
|
|
|
## 未完成(按计划属于后续阶段,不是本脚手架遗漏)
|
|
|
|
|
|
|
|
|
|
|
|
1. **Handler 业务(3+29)**:`processing/HandlerRegistry` 仅注册骨架,翻译属阶段 2/3。
|
|
|
|
|
|
2. **codec 实装**:vendor 复用 legacy `entity/msg` POJO + Jackson XML(ACMA-6 选型),
|
|
|
|
|
|
阶段 1 后续项。
|
|
|
|
|
|
3. **依赖版本锁定**:`gradle/libs.versions.toml` 中版本为计划口径,需阶段 0
|
|
|
|
|
|
「Micronaut×现网 Eureka 互操作冒烟 + logstash + ES REST」通过后固化。
|
2026-09-07 10:27:44 +08:00
|
|
|
|
4. **自有 PG 数据层 + InboxPoller**(ACM2-12):`infra/persistence/Repositories.kt` 目前是接口
|
|
|
|
|
|
(Micronaut Data JDBC on PG + 信箱适配层 CminmsgMailbox/OutboxMailbox + JDBC 轮询入队
|
|
|
|
|
|
属 U05 批次),主泵/调度循环以接口驱动,纯逻辑已抽离可单测。
|
|
|
|
|
|
5. **信箱适配层与共享库边界**(ACM2-12):上游外部写 `CMINMSGS`;本系统 JDBC 轮询读 +
|
|
|
|
|
|
处理回填写;出站写 `COUTMSGS`(mailbox.shared-mysql 配置段已占位);入队/回填的
|
2026-09-07 08:21:11 +08:00
|
|
|
|
外部副作用/补偿模型属 U05 批次。
|
2026-09-06 16:13:50 +08:00
|
|
|
|
|
2026-09-07 08:21:11 +08:00
|
|
|
|
## 数据库初始化(ACM2-12 口径)
|
2026-09-06 17:58:39 +08:00
|
|
|
|
|
2026-09-07 08:21:11 +08:00
|
|
|
|
**自有 PostgreSQL**(唯一自有库):`db/migration/V1.0.0__own_pg_pipeline.sql` 建
|
|
|
|
|
|
PROC_STATE / MSG_EVENT / PUMP_JOB / REQ_TRACK / REF_MASTER(PG 方言)。全新库直接执行即可,
|
|
|
|
|
|
无 legacy 前置。
|
2026-09-06 17:58:39 +08:00
|
|
|
|
|
2026-09-07 10:27:44 +08:00
|
|
|
|
**共享 MySQL(cdairport,他人系统库)**:本系统**不建表/schema**,仅信箱 DML——上游外部写
|
|
|
|
|
|
`CMINMSGS`;本系统 JDBC 轮询读 + 处理回填;出站写 `COUTMSGS`(他人读取发送);表结构与
|
|
|
|
|
|
保留策略归库方管理。部署前需确认共享库 CMINMSGS 已存在(他人系统提供);本仓库不声明其 schema。
|
2026-09-07 08:21:11 +08:00
|
|
|
|
|
2026-09-07 10:27:44 +08:00
|
|
|
|
- **事务模型**:与共享库交互均为外部副作用(ACM2-12)——主路径=上游外部写信箱 →
|
|
|
|
|
|
JDBC 轮询发现新信 → 自有 PG 建 PENDING 入队(失败重扫补建);HTTP `/cminmsgs/send`
|
|
|
|
|
|
为 compat 写路径;处理成功回填 DATE_PROCESSED/STATUS 为最终一致。
|
2026-09-07 08:21:11 +08:00
|
|
|
|
- **快照 gen**:随航班动态同在 Redis(gen→Redis 协议属 U09,当前为过渡占位)。
|
|
|
|
|
|
- **阶段 B(FLIGHT_STATE)**:缓做不落表。
|
|
|
|
|
|
- 影子对拍:自有 PG 开独立 schema;共享信箱为单信箱无法双写,影子输入=只读水位/回放口径。
|
2026-09-06 17:58:39 +08:00
|
|
|
|
|
2026-09-07 14:15:07 +08:00
|
|
|
|
|
|
|
|
|
|
## 本地开发依赖中间件栈(Podman / Docker Compose,ACM2-13)
|
|
|
|
|
|
|
|
|
|
|
|
仓库根目录提供兼容 Podman Compose 与 Docker Compose 的开发中间件栈 `compose.yaml`,包含:
|
|
|
|
|
|
- **共享信箱 MySQL**(`mysql:8.4` LTS,端口 3306,库 `cdairport`):容器启动时自动执行 `deploy/dev/mysql-init/01-mailbox.sql` 创建本地联调所需的 `CMINMSGS`、`CMINMSGS_HST`、`COUTMSGS` 模拟表。
|
|
|
|
|
|
- **自有 PostgreSQL**(`postgres:17-alpine`,端口 5432,库 `msgx`):容器提供干净数据库,应用启动时由 Flyway(`db/migration/V1.0.0__own_pg_pipeline.sql`)自动建自有表。
|
|
|
|
|
|
- **Redis / 动态与快照**(开源分叉 `valkey/valkey:8-alpine`,端口 6379):100% 兼容 Redis 7.2+ 协议与 Lua 脚本,支持 `--appendonly yes`。
|
|
|
|
|
|
- **Kafka**(`apache/kafka:3.8.0` KRaft 单节点,端口 9092):listener `PLAINTEXT://localhost:9092`,`default.replication.factor=1`,已预配幂等生产者与 acks=all 所需的单节点参数。
|
|
|
|
|
|
|
|
|
|
|
|
### 快速启动
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
|
|
|
|
|
# 1. 复制环境变量示例(可按需修改口令与端口)
|
|
|
|
|
|
cp .env.example .env
|
|
|
|
|
|
|
|
|
|
|
|
# 2. 启动开发依赖栈(支持 docker compose 或 podman compose)
|
|
|
|
|
|
docker compose up -d
|
|
|
|
|
|
|
|
|
|
|
|
# 3. 检查各服务健康状态(均为 healthy)
|
|
|
|
|
|
docker compose ps
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
### 环境变量与应用映射
|
|
|
|
|
|
|
|
|
|
|
|
| 环境变量 | 说明 | 示例默认值 | 应用配置映射(application.yml) |
|
|
|
|
|
|
|---|---|---|---|
|
|
|
|
|
|
| `MSGX_MAILBOX_URL` | 共享信箱 MySQL JDBC URL | `jdbc:mysql://localhost:3306/cdairport?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai&characterEncoding=utf8mb4` | `mailbox.shared-mysql.url` |
|
|
|
|
|
|
| `MSGX_MAILBOX_USER` | 共享信箱 MySQL 用户名 | `msgx_dev` | `mailbox.shared-mysql.username` |
|
|
|
|
|
|
| `MSGX_MAILBOX_PASSWORD` | 共享信箱 MySQL 密码 | `msgx_dev_pass` | `mailbox.shared-mysql.password` |
|
|
|
|
|
|
| `MSGX_PG_URL` | 自有 PostgreSQL JDBC URL | `jdbc:postgresql://localhost:5432/msgx` | `datasources.default.url` |
|
|
|
|
|
|
| `MSGX_PG_USER` | 自有 PostgreSQL 用户名 | `msgx_dev` | `datasources.default.username` |
|
|
|
|
|
|
| `MSGX_PG_PASSWORD` | 自有 PostgreSQL 密码 | `msgx_dev_pass` | `datasources.default.password` |
|
|
|
|
|
|
| `MSGX_REDIS_URI` | Redis/Valkey 连接串 | `redis://localhost:6379` | `redis.uri` |
|
|
|
|
|
|
| `MSGX_KAFKA_SERVERS` | Kafka bootstrap brokers | `localhost:9092` | `kafka.bootstrap.servers` |
|
|
|
|
|
|
| `MSGX_KAFKA_ACKS` | 生产确认级别 | `all` | `kafka.producers.default.acks` |
|
|
|
|
|
|
| `MSGX_KAFKA_IDEMPOTENCE` | 幂等生产者开关 | `true` | `kafka.producers.default.enable-idempotence` |
|
|
|
|
|
|
| `MSGX_KAFKA_MAX_IN_FLIGHT` | 单连接最大在途请求数 | `1` | `kafka.producers.default.max-in-flight-requests-per-connection` |
|
|
|
|
|
|
|
|
|
|
|
|
### 切流前 Kafka Broker 版本确认
|
|
|
|
|
|
|
|
|
|
|
|
生产契约以 `user-stories.md` US-07 / §7-6 为准:对接 Kafka 2.8+ / 3.x+,生产者强制 `acks=all`、`enable.idempotence=true` 与 `max.in.flight.requests.per.connection=1`,**严禁非幂等降级**。README 不提供生产降级环境变量组合。
|
|
|
|
|
|
|
|
|
|
|
|
旧系统 `msgexchange-api` 底层依赖 `kafka-clients:0.10.1.1`;现网 Broker 确切版本须在切流前实测确认:
|
|
|
|
|
|
|
|
|
|
|
|
1. **版本探测**:切流前通过本栈工具探测目标集群 API 能力:
|
|
|
|
|
|
```bash
|
|
|
|
|
|
docker exec msgx-dev-kafka /opt/kafka/bin/kafka-broker-api-versions.sh --bootstrap-server <TARGET_IP>:9092
|
|
|
|
|
|
```
|
|
|
|
|
|
2. **门禁判定**:若输出中 `InitProducerId(22)` 为 **可用** → 保持现代高可靠默认(`acks=all`、`idempotence=true`、`max.in.flight=1`)。
|
|
|
|
|
|
3. **阻塞切流**:若 `InitProducerId(22)` 为 **UNSUPPORTED**(Broker < 0.11)→ **阻塞切流**,须升级 Broker 或经架构豁免(ACM2-1 基础设施升级门禁);降级参数仅可作为经批准的 runbook 附录,**不得**作为生产验收口径与 README 默认配置并存。
|
|
|
|
|
|
|
2026-09-06 16:13:50 +08:00
|
|
|
|
## 构建
|
|
|
|
|
|
|
|
|
|
|
|
```bash
|
2026-09-06 17:58:39 +08:00
|
|
|
|
./gradlew build # 需网络拉取依赖;内网环境见 gradle.properties 注释
|
2026-09-06 20:53:14 +08:00
|
|
|
|
./gradlew test # 纯逻辑单测(identity / schd 聚合 / 配置绑定 / 管道语义)
|
2026-09-07 07:39:57 +08:00
|
|
|
|
MICRONAUT_ENVIRONMENTS=dev ./gradlew run # dev stub 冒烟:内存 stub,无需 DB/Redis/Kafka/Eureka
|
2026-09-06 16:13:50 +08:00
|
|
|
|
```
|
|
|
|
|
|
|
2026-09-07 07:39:57 +08:00
|
|
|
|
> **进程级 dev 冒烟(2026-09-07 修复并实测通过)**:此前 `./gradlew run` 因未声明
|
|
|
|
|
|
> `application.mainClass` 报 "No main class specified"(已补,见 build.gradle.kts);随后实测又暴露
|
|
|
|
|
|
> dev profile 三处装配问题并已修复(application-dev.yml):stub 模式未排除 DataSource
|
|
|
|
|
|
> (`datasources.default.enabled=false`);micronaut 自带 Redis/Kafka 健康指示器在无 broker 时把
|
|
|
|
|
|
> /health 拖成 500(dev 关闭 redis.health/kafka.health,健康由自定义指示器承担);管理端点前缀误用
|
|
|
|
|
|
> `micronaut.endpoints.*`(正确为顶层 `endpoints.*`,/env、/beans 这才真正放开);另关闭 eureka
|
|
|
|
|
|
> discovery。当前 `MICRONAUT_ENVIRONMENTS=dev ./gradlew run` **无需任何环境变量/外部依赖**即可启动,
|
2026-09-07 10:27:44 +08:00
|
|
|
|
> compat HTTP `POST /cminmsgs/send`(application/json)返回记录 ID,`/health` UP。
|
2026-09-07 14:15:07 +08:00
|
|
|
|
> 已知边界:text/plain compat 写 415 属 U16 缺口(契约对拍后固化);`application-dev.yml` 数据源配置
|
|
|
|
|
|
> 已对齐为自有 PG 与共享 MySQL 信箱(ACM2-12/13);测试侧端到端语义由 PipelineSmokeTest
|
|
|
|
|
|
> (内嵌上下文,compat 写路径)覆盖。**生产主路径**(JDBC 轮询 `InboxPoller`)属 U05,dev stub 尚未覆盖。
|
2026-09-07 07:39:57 +08:00
|
|
|
|
|
2026-09-06 17:58:39 +08:00
|
|
|
|
> 注解处理:Kotlin 侧经 KSP(`kotlin-ksp` + `micronaut-inject-kotlin`)生成 Micronaut
|
|
|
|
|
|
> BeanDefinition(U01);若 build 产物缺少 `*$Definition` 类,先检查 KSP 是否生效。
|
2026-09-06 20:53:14 +08:00
|
|
|
|
> dev/shadow 冒烟装配:`msgx.stubs=true`(内存仓储/适配层,见 infra/stub)+
|
|
|
|
|
|
> `msgx.pipeline.autostart=true`(PipelineLifecycle 拉起专用线程,U07);生产默认两者关闭。
|
2026-09-06 17:58:39 +08:00
|
|
|
|
|
2026-09-06 22:30:03 +08:00
|
|
|
|
## 文档
|
|
|
|
|
|
|
2026-09-08 18:50:34 +08:00
|
|
|
|
从 [设计文档入口](docs/README.md) 开始阅读;最新完成度见
|
|
|
|
|
|
[ACM2-29 核查与简化计划](docs/acm2-29-audit-and-simplification.md)。
|
|
|
|
|
|
|
2026-09-07 10:27:44 +08:00
|
|
|
|
- [docs/architecture.md](docs/architecture.md):架构速览——**中间件定位**、总体拓扑(JDBC 轮询主路径)、
|
|
|
|
|
|
上下游边界、模块职责、关键决策、数据边界、部署与安全姿态、可观测性、就绪度。
|
|
|
|
|
|
- [docs/design.md](docs/design.md):设计细节——系统边界、状态机与错误分类、数据模型、
|
2026-09-07 14:15:07 +08:00
|
|
|
|
核心流程语义(流程 1 主路径/compat 分述)、失败/重试/重放、不变量落点、参数表、已知缺口。
|
|
|
|
|
|
- [docs/user-stories.md](docs/user-stories.md):阶段 A US-01~US-14、延后清场 US-15、上线 Epic、
|
|
|
|
|
|
legacy HTTP 去留及逐项文档 TODO;包含验收标准、依赖、实现差距与待确认问题。
|
2026-09-07 15:10:57 +08:00
|
|
|
|
(原 ACM2-15~22 文档整改清单 user-stories-todo.md 已收敛完成并移除,跟踪记录见 Plane。)
|
2026-09-08 18:50:34 +08:00
|
|
|
|
- [docs/decision-flight-state.md](docs/decision-flight-state.md):有效决策摘要——单库权威已采纳,固定槽位方案已撤销;历史全文另存。
|
2026-09-07 08:29:49 +08:00
|
|
|
|
- [docs/legacy/](docs/legacy/):外部参考/基线材料(自 legacy 仓库拷贝,非本系统文档)——
|
2026-09-07 10:27:44 +08:00
|
|
|
|
`msgexchange-api-legacy-user-stories.md`(legacy 行为对拍基线,ACMA-4)、`unisysaodbsis.xsd`、
|
|
|
|
|
|
`SIS_AODB_RMS-V0.1.md`(消息结构唯一事实源;CIIMS 中间件交换模型)。
|
2026-09-06 22:30:03 +08:00
|
|
|
|
|
2026-09-06 16:13:50 +08:00
|
|
|
|
## 关联
|
|
|
|
|
|
|
2026-09-07 10:27:44 +08:00
|
|
|
|
Plane **`airport_chengdu_msgexchange_v2`(ACM2,现行入口)**:ACM2-3(综合架构 v4,
|
|
|
|
|
|
架构权威,存储边界按 ACM2-12 修订;ACM2-11 为决策史)、ACM2-4(脚手架跟踪)、ACM2-10(评审与实施计划
|
|
|
|
|
|
U01–U30)、ACM2-12(存储边界与共享信箱决策);ACMA 系列仅作归档历史/迁移来源
|
2026-09-07 08:21:11 +08:00
|
|
|
|
(ACMA-8 v4 / ACMA-6 选型 / ACMA-9 JDK 口径在归档中可溯)。
|