Files
msgexchange-v2/README.md
T

169 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# msgexchange-v2(机场上游报文处理中间件)
**系统角色**:消费 CIIMS/AODB 等上游经共享 MySQL 信箱(`CMINMSGS`)投递的 XML 报文,
解析处理后维护自有 PostgreSQL 航班当前态并向 Kafka / 出站信箱投递——**中间件**,非报文源系统。
依据 **ACMA-8 v4 综合架构**(单写者严格 FIFO 管道)与 **ACMA-6 技术选型**
Micronaut 5.1 + Kotlin 2.3)搭建;**存储边界与阶段 B 按 ACM2-11/ACM2-12 定案**
(自有 PostgreSQL 维护内部状态,共享 MySQL 仅作信箱边界)。
本仓库独立于 legacy `msgexchange-api`Java 8 / Spring Boot 1.5 / Maven)——
过渡期两套系统并存(影子对拍→切流→旧仓库冻结),legacy 维护不受本仓库影响。
> **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 决策 → PostgreSQL 航班当前态 |
| **出站** | Kafka + `COUTMSGS` | 向下游推送 msg/schd;请求类报文写出站信箱 |
与 SIS / legacy 一致:本系统**不**替代 CIIMS 落信,**不**生成原始 AODB 业务报文。
## 包结构 → ACMA-8 架构映射
| 包 | 职责 | 对应 ACMA-8 |
|---|---|---|
| `ingress/` | Ingress & InboxJDBC 轮询共享信箱发现新信 → 自有 PG 入队(+ HTTP compat 写路径),不解析报文 | 流程 1,I3 |
| `processing/` | Processing 主泵:严格 FIFO 领取、identity 绑定、纯函数决策、事务2 | 流程 2/4I1/I2/I5 |
| `delivery/` | Delivery & Projection:每 target 严格 FIFO 投递、schd 聚合 | 流程 3 |
| `reference/` | Reference & Query21 类同步 + 15 类请求状态机 | 流程 6 |
| `jobs/` | 泵作业:ARCHIVE / HISTORY_SWEEP / PROJECTION_REBUILD | 流程 4/5/7I4 |
| `codec/` | SIS XML codec(注解 wire DTO → 领域载荷,禁 DTD/外部实体) | 决策 4 前置 |
| `domain/` | 领域模型:Decision、事件、状态机枚举、Phase 开关 | I1I5 |
| `config/` | `PipelineProps` 参数表(ACMA-8 参数初值,`msgx.*` | — |
| `infra/` | 仓储接口、stub、健康、重试策略 | 数据模型节 |
## 资源
- `docs/legacy/SIS_AODB_RMS-V0.1.md` + `docs/legacy/unisysaodbsis.xsd`**消息结构唯一事实源**
wire 契约冻结,自 legacy 仓库复制以自包含;codec 实装依据,ACM2-2/ACM2-3)。
- `db/migration/V1__flight_state_baseline.sql`**自有 PostgreSQL**(唯一自有库)的航班状态与处理管道表结构;
共享 MySQLCMINMSGS/COUTMSGS)仅信箱 DML,不建表。
- `lua/batch_delete.lua`:3:30 清场批量删除(仅 ES 写成功集,I4)。
- `application.yml`:口令全部环境变量外置(零入库);`datasources.default`=自有 PGenabled=false
待 U05)、`mailbox.shared-mysql`=共享信箱;`msgx.phase` 权威口径(A 现役;B 缓做);
pipeline 参数 = ACMA-8 参数表初值。
## 未完成(按计划属于后续阶段,不是本脚手架遗漏)
1. **Handler 业务(3+29**`processing/HandlerRegistry` 仅注册骨架,翻译属阶段 2/3。
2. **依赖版本锁定**`gradle/libs.versions.toml` 中版本为计划口径,需阶段 0
「Micronaut×现网 Eureka 互操作冒烟 + logstash + ES REST」通过后固化。
3. **自有 PG 数据层 + InboxPoller**ACM2-12):`infra/persistence/Repositories.kt` 目前是接口
Micronaut Data JDBC on PG + 信箱适配层 CminmsgMailbox/OutboxMailbox + JDBC 轮询入队
属 U05 批次),主泵/调度循环以接口驱动,纯逻辑已抽离可单测。
4. **信箱适配层与共享库边界**ACM2-12):上游外部写 `CMINMSGS`;本系统 JDBC 轮询读 +
处理回填写;出站写 `COUTMSGS`mailbox.shared-mysql 配置段已占位);入队/回填的
外部副作用/补偿模型属 U05 批次。
## 数据库初始化(ACM2-12 口径)
**自有 PostgreSQL**(唯一自有库):Flyway 执行 `db/migration/V1__flight_state_baseline.sql`,建立
航班当前态、明细表、处理终态与 outbox 等表(PG 方言)。这是**单基线**:原 V2–V10 的净结构已
合并其中,全新库直接执行即可,无 legacy 前置。已按旧链(V1–V10)迁移过的库版本链与校验和都
对不上,必须重建 schema 或删除数据卷后重跑,禁止手工 `repair` 或改写 `flyway_schema_history`
**共享 MySQLcdairport,他人系统库)**:本系统**不建表/schema**,仅信箱 DML——上游外部写
`CMINMSGS`;本系统 JDBC 轮询读 + 处理回填;出站写 `COUTMSGS`(他人读取发送);表结构与
保留策略归库方管理。部署前需确认共享库 CMINMSGS 已存在(他人系统提供);本仓库不声明其 schema。
- **事务模型**:与共享库交互均为外部副作用(ACM2-12)——主路径=上游外部写信箱 →
JDBC 轮询发现新信 → 自有 PG 建 PENDING 入队(失败重扫补建);HTTP `/cminmsgs/send`
为 compat 写路径;处理成功回填 DATE_PROCESSED/STATUS 为最终一致。
- **航班状态**:写入自有 PostgreSQL;完整规则见 [implementation.md](docs/implementation.md)「航班域」。
- 影子对拍:自有 PG 开独立 schema;共享信箱为单信箱无法双写,影子输入=只读水位/回放口径。
## 本地开发依赖中间件栈(Podman / Docker ComposeACM2-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__flight_state_baseline.sql`)自动建自有表。
- **Valkey**`valkey/valkey:8-alpine`,端口 6379):本地中间件兼容服务,不承担航班状态权威或日计划处理。
- **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 版本确认
生产契约以 [requirements.md](docs/requirements.md) `US-07` 为准:对接 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 &lt; 0.11)→ **阻塞切流**,须升级 Broker 或经架构豁免(ACM2-1 基础设施升级门禁);降级参数仅可作为经批准的 runbook 附录,**不得**作为生产验收口径与 README 默认配置并存。
## 构建
```bash
./gradlew build # 需网络拉取依赖;内网环境见 gradle.properties 注释
./gradlew test # 纯逻辑单测(identity / schd 聚合 / 配置绑定 / 管道语义)
MICRONAUT_ENVIRONMENTS=dev ./gradlew run # dev stub 冒烟:内存 stub,无需 DB/Redis/Kafka/Eureka
```
> **进程级 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 拖成 500dev 关闭 redis.health/kafka.health,健康由自定义指示器承担);管理端点前缀误用
> `micronaut.endpoints.*`(正确为顶层 `endpoints.*`/env、/beans 这才真正放开);另关闭 eureka
> discovery。当前 `MICRONAUT_ENVIRONMENTS=dev ./gradlew run` **无需任何环境变量/外部依赖**即可启动,
> compat HTTP `POST /cminmsgs/send`application/json)返回记录 ID`/health` UP。
> 已知边界:text/plain compat 写 415 属 U16 缺口(契约对拍后固化);`application-dev.yml` 数据源配置
> 已对齐为自有 PG 与共享 MySQL 信箱(ACM2-12/13);测试侧端到端语义由 PipelineSmokeTest
> (内嵌上下文,compat 写路径)覆盖。**生产主路径**(JDBC 轮询 `InboxPoller`)属 U05dev stub 尚未覆盖。
> 注解处理:Kotlin 侧经 KSP`kotlin-ksp` + `micronaut-inject-kotlin`)生成 Micronaut
> BeanDefinitionU01);若 build 产物缺少 `*$Definition` 类,先检查 KSP 是否生效。
> dev/shadow 冒烟装配:`msgx.stubs=true`(内存仓储/适配层,见 infra/stub+
> `msgx.pipeline.autostart=true`PipelineLifecycle 拉起专用线程,U07);生产默认两者关闭。
## 文档
`docs/` 是唯一设计依据;从 [设计文档入口](docs/README.md) 开始阅读(职责、事实归属、ID 语法与引用纪律都在那里)。顶层 6 个文件:
- [architecture.md](docs/architecture.md):系统边界、模块职责、存储归属、总体流程与 `D1``D4` 决策。
- [requirements.md](docs/requirements.md):阶段范围与非目标、`US-xx` / `OPS-x` 验收目标、需求覆盖与依赖。
- [specification.md](docs/specification.md):术语、契约 `C-x`、前提 `PRE-x`、不变量 `INV-x`、声明边界 `CLM-x`、待确认 `Q`、已知偏差 `G`、验证映射。
- [implementation.md](docs/implementation.md):管道机制与航班域——数据模型、状态机、事务、投递、作业与恢复,航班权威模型与合并语义。
- [reference.md](docs/reference.md):参数 `PARAM:<key>`、指标与健康、模块与代码入口、错误分类。
- [legacy/](docs/legacy/):外部协议与旧系统基线(`SIS_AODB_RMS-V0.1.md` 为消息结构唯一事实源、`unisysaodbsis.xsd`、legacy 行为对拍基线、历史决策记录)。
实现进度与缺口处置在 Plane(ACM2)。运行规程在上线/切流前另立 `docs/runbooks/`,不进入顶层。