feat(processing): 领域/投影/终态三步提交与 FlightProjectionPort(ACM2-79)
PIPELINE_LOCK 跨 Redis 写;MSG_EVENT HELD→PENDING;Redis 失败不终态不投递;V3 迁移。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+12
-8
@@ -60,13 +60,15 @@ msgexchange-v2 怎么处理报文:记录模型、状态机、事务边界、
|
||||
→ FAILED(等待退避重试)
|
||||
→ DEAD(MALFORMED / PROTOCOL / EXHAUSTED,均需人工处置)
|
||||
|
||||
投递:PENDING → SENT
|
||||
→ PENDING(退避后重试)
|
||||
→ DEAD(重试耗尽,记录保留作死信)
|
||||
投递:HELD → PENDING → SENT
|
||||
→ PENDING(退避后重试)
|
||||
→ DEAD(重试耗尽,记录保留作死信)
|
||||
```
|
||||
|
||||
`SUCCEEDED`/`SKIPPED`/`DEAD` 是终态,不挡后续;`FAILED` 仍占队头。用尽重试 → `DEAD(EXHAUSTED)`。错误分类与重放白名单见 [reference.md](reference.md)。
|
||||
|
||||
`HELD` 是尚未放行的待发事件:领域事务登记,投影写成功后由终态事务转 `PENDING`(「事务边界」)。
|
||||
|
||||
## 4. 收报
|
||||
|
||||
### 4.1 收报
|
||||
@@ -116,9 +118,9 @@ processOne(head):
|
||||
载荷缺失 → DEAD(MALFORMED)
|
||||
整包协议拒绝 → DEAD(PROTOCOL),不落半包
|
||||
5. 业务型成功,分三步(INV-3、INV-10):
|
||||
① 事务提交:航班变更 + 待发事件
|
||||
① 事务提交:航班变更 + 待发事件(登记为 HELD,投递领不到)
|
||||
② 写 Redis 航班快照;失败 → 保持未完成,下轮重处理
|
||||
③ 事务提交:SUCCEEDED + 回填意图
|
||||
③ 事务提交:SUCCEEDED + 回填意图 + 待发事件放行(HELD → PENDING)
|
||||
6. 结束:主泵不做回填;回填意图已随终态落库,由扫描补写信箱标记
|
||||
```
|
||||
|
||||
@@ -130,15 +132,17 @@ processOne(head):
|
||||
|---|---|---|---|---|
|
||||
| 收报入队(`insertIfAbsent`) | 是 | 否 | 否 | 同库事务 |
|
||||
| 身份首次绑定 | 否 | 否 | 否 | 单语句 + 唯一约束 |
|
||||
| 业务型领域变更(航班变更 + 待发事件) | 是 | 是 | 是 | 同库事务(`INV-3`) |
|
||||
| 业务型领域变更(航班变更 + 待发事件) | 是 | 是 | 是 | 同库事务(`INV-3`);事件落 `HELD` |
|
||||
| Redis 航班快照写 | 否 | 是(处理步骤锁跨越本步) | 否 | 外部副作用,不在 PG 事务内;写成功是终态事务的前置(`INV-10`) |
|
||||
| 业务型终态(`SUCCEEDED` + 回填意图) | 是 | 是 | 否 | 同库事务(`INV-3`) |
|
||||
| 业务型终态(`SUCCEEDED` + 回填意图 + 事件放行) | 是 | 是 | 否 | 同库事务(`INV-3`) |
|
||||
| 非业务型终态(`MALFORMED` / `PROTOCOL` / `SKIPPED` / `EXHAUSTED`) | 否 | 否 | 否 | 单语句(终态与回填意图同一条 UPDATE) |
|
||||
| 航班历史清理的物理删除 | 是 | 是(落实 `US-14` AC4) | 是 | 同库事务:复查判据 + 历史写入成功后删除 |
|
||||
| 回填(信箱标记 + `BACKFILL_AT`) | 否 | 否 | 否 | 跨库两次单写;幂等可重跑 |
|
||||
| 人工重放(批量改回 `PENDING`) | 否 | 否 | 否 | 单语句批量;`MessageLifecycleGate` 与回填互斥 |
|
||||
|
||||
航班变更与终态不在同一事务,中间夹 Redis 写(`INV-3`、`INV-10`)。`PIPELINE_LOCK` 跨 Redis 写,与历史清理互斥(`US-14` AC4);无第二写者时不额外串行。
|
||||
航班变更与终态不在同一事务,中间夹 Redis 写(`INV-3`、`INV-10`)。三步跑在同一条数据库连接上:进处理步骤先在该连接取会话级咨询锁(`pg_advisory_lock`),两次事务复用这条连接,整步结束才解锁。行锁随提交释放,单靠它盖不住提交之后的 Redis 写,所以第二个写者(历史清理)在自己的事务里也要先取同一把咨询锁,再照旧锁 `PIPELINE_LOCK` 行,两边因此在整段内互斥(`US-14` AC4);无第二写者时不额外串行。
|
||||
|
||||
投影失败时领域事务已提交而终态未写,`MSG_EVENT` 行停在 `HELD`:投递只领 `PENDING`,Kafka 不会先于处理完成发出(`INV-3`)。下一轮重处理按 `MSG_ID` 先清掉上一轮的 `HELD` 行再重新登记,崩溃重启后既不留悬挂行,也不把同一次变更投两遍。
|
||||
|
||||
### 5.4 历史积压
|
||||
|
||||
|
||||
+4
-1
@@ -54,6 +54,8 @@
|
||||
| `msgx.identity.include-day-boundary` | `false` | 去重时是否把日期算进消息身份;受 `C-3` 约束,不能随意改变 | 默认关闭 |
|
||||
| `msgx.health.backlog-cache-ttl-ms` | `30000` ms | `/health` 与 `/metrics` 共用的未处理消息统计最多缓存多久;`0` 表示每次重算 | 暂定 |
|
||||
| `msgx.history.history-store-enabled` | `false` | 是否启用历史航班写入;关闭时不删除实时航班 | 默认关闭 |
|
||||
| `msgx.redis.enabled` | `false` | 是否把航班快照写进 Redis 查询投影;关闭时投影写入是空操作(`G-REDIS-PROJECTION`) | 默认关闭 |
|
||||
| `msgx.redis.flight-key` | `flightInfo` | 航班快照所在的 Redis 哈希键,字段名是 `FLID` | 沿用旧系统 |
|
||||
| `msgx.history.planned-age-days` | `3` 天 | `US-14` AC2 条件 1:计划时间早于当前超过该天数视为已结束 | `US-14` AC2 |
|
||||
| `msgx.history.cancelled-hours` | `1` 小时 | `US-14` AC2 条件 2:取消时间早于当前超过该窗口视为已结束 | `US-14` AC2 |
|
||||
| `msgx.history.diverted-hours` | `1` 小时 | `US-14` AC2 条件 3:备降且计划时间早于当前超过该窗口;备降依据 `FDIV`(`DDES`/`DDIR`)落地前不参与判定(`Q3`、ACM2-100) | `US-14` AC2 |
|
||||
@@ -90,7 +92,7 @@
|
||||
|
||||
**缺值**:带环境变量占位的必需键(`MSGX_PG_URL`、`MSGX_MAILBOX_URL`、`MSGX_KAFKA_SERVERS` 等)缺失时由 DI 解析失败拒绝启动,无需自检代码。
|
||||
|
||||
**显式开关(非配置错误)**:`msgx.stubs`、`datasources.default.enabled`、`mailbox.shared-mysql.enabled`、`msgx.history.history-store-enabled`、`msgx.pipeline.autostart`。默认关闭是"未接入"的显式声明,不判违规;只有 `msgx.pipeline.autostart=true` 才要求依赖齐备。Kafka 运行时不可达不是配置错误,归 `/health` 与投递指标告警(`OPS-2`)。
|
||||
**显式开关(非配置错误)**:`msgx.stubs`、`datasources.default.enabled`、`mailbox.shared-mysql.enabled`、`msgx.history.history-store-enabled`、`msgx.redis.enabled`、`msgx.pipeline.autostart`。默认关闭是"未接入"的显式声明,不判违规;只有 `msgx.pipeline.autostart=true` 才要求依赖齐备。Kafka 运行时不可达不是配置错误,归 `/health` 与投递指标告警(`OPS-2`)。
|
||||
|
||||
## 指标与健康
|
||||
|
||||
@@ -121,6 +123,7 @@
|
||||
| 读取信箱与 HTTP 入口 | `ingress/InboxPoller.kt`、`ingress/InboxController.kt` |
|
||||
| XML 解析 | `codec/JacksonXmlCodec.kt`、`codec/SisWireMapper.kt` |
|
||||
| 顺序处理与航班变更 | `processing/Pump.kt`、`processing/DynamicProcessors.kt`、`processing/ScheduleProcessor.kt` |
|
||||
| 三步提交与 Redis 投影 | `processing/FlightCommit.kt`、`processing/FlightProjection.kt`、`infra/projection/` |
|
||||
| 写回信箱与发送 Kafka | `processing/BackfillService.kt`、`delivery/Dispatcher.kt`、`infra/kafka/KafkaDeliveryPort.kt` |
|
||||
| 定时任务 | `jobs/JobRunner.kt`、`jobs/HistorySweepJob.kt`、`jobs/EventCleanupJob.kt` |
|
||||
| 数据库读写与手动重试 | `infra/persistence/jdbc/`、`infra/retry/` |
|
||||
|
||||
@@ -153,7 +153,7 @@
|
||||
| `G-FLOP-UNMAPPED` | [XSD](legacy/unisysaodbsis.xsd) FLOP 字段映射不全 | `US-05` |
|
||||
| `G-MAFL` | 主航班共享列表未做 | `US-06` AC2 |
|
||||
| `G-PROC-CLEANUP` | 处理记录到期清理未做 | `US-11` |
|
||||
| `G-REDIS-PROJECTION` | Redis 快照写入与删除未做 | `US-05`、`US-06`、`US-07`、`US-12` |
|
||||
| `G-REDIS-PROJECTION` | Redis 快照写入与删除未做:投影端口与三步提交时序已就位,真实 Redis 客户端未接通,日计划覆盖范围的缺席清扫也未做 | `US-05`、`US-06`、`US-07`、`US-12` |
|
||||
| `G-REF-DATA` | 静态参考数据处理与 admin-api 直读未做 | `US-13` |
|
||||
| `G-REQ-OPEN-UNIQUE` | 同类型未处理完时不允许再发,未做 | `US-09` |
|
||||
| `G-REQ-TRACK` | 出站请求跟踪未做 | `US-09` |
|
||||
|
||||
Reference in New Issue
Block a user