Files
msgexchange-v2/docs/reference.md
T
windyboy 6eade95a97 docs: 拆分契约/前提/参数文档,合并消息生命周期并收敛设计裁决
- design.md 合并 message-lifecycle.md(后者保留跳转 stub),去重并改用稳定 ID 引用
- 新增 invariants.md(前提/不变量/声明边界/验证映射)、contracts.md(对外条款与 Q 台账)、
  reference.md(参数/指标/模块/错误分类)
- architecture/flight-state/user-stories/README 同步重划引用;README 废止「引用章节号」
- 裁决收敛:R 按超期而非次数放弃、清除前提含放弃清单、航班表写者互斥、head-deadline 仅告警、
  超期判据用本地入队时间、投递批次读取时刻冻结、schd 只进不退与条件标记、FLID 复用为前提
- 删除 runbooks 与 CI 防漂移校验:设计阶段不产出面向执行期的产物

Refs: ACM2-42..51
2026-09-11 15:48:14 +08:00

115 lines
10 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.
# 参考注册表:参数、指标、模块、错误分类
本文件是**可派生事实**的唯一出处:参数默认值、指标名、模块入口、错误分类。正文(design.md)只引 `PARAM:<完整键>`,不写数值。
维护规则:新增或改名一个 `msgx.*` 键、增删一个指标名,必须同步本文件(人工核对,本项目不做 CI 校验)。`mailbox.*``datasources.*``kafka.*` 属基础设施键,按 §1.3 成组登记。
## 1. 参数注册表
「依据」列含义:**契约** = 由 contracts.md 的 `C-x` 决定;**现役** = 沿用 legacy 行为基线;**假定** = 无依据的占位值,必须在对应 `Q` 关闭后重评;**安全默认** = 关闭态,需显式开启。
### 1.1 管道节奏与重试(`msgx.pipeline.*`
| 参数 | 默认 | 单位 | 依据 | 说明 |
|---|---|---|---|---|
| `msgx.pipeline.poll-interval` | `1s` | Duration | 现役 | 收报轮询节奏;决定队头与空洞检查频率 |
| `msgx.pipeline.claim-batch` | `50` | 条 | 假定 | 单轮领取上限;过大延长单轮事务 |
| `msgx.pipeline.max-attempts` | `5` | 次 | 假定 | 处理与投递共用;达到即转 `DEAD(EXHAUSTED)` |
| `msgx.pipeline.backoff-ms` | `[1000,2000,4000,8000]` | ms / 档 | 假定 | **档位数必须 = `max-attempts 1`**,启动自检拦截错位 |
| `msgx.pipeline.backoff-cap-ms` | `60000` | ms | 假定 | 单档封顶;默认表内无档触及 |
| `msgx.pipeline.head-deadline` | `10m` | Duration | 假定 | **仅用于队头滞留告警**,不作终态判据(判据只由 `max-attempts`)。代码注释仍写「毒丸升级」,属待收敛的表述差 `[G-HEAD-DEADLINE]` |
| `msgx.pipeline.max-commit-delay` | `5m` | Duration | **假定(无依据)** | 空洞老化阈值;由 `C-2` 决定,**不可由 SIS `Expiry` 推导**`Q2` |
| `msgx.pipeline.overdue-backfill``R` | `30d` | Duration | 契约(`R ≤ R_keep`) | 进入强补写窗口、**取消退避**的阈值;**不是兜底保证**,不保护重放窗口(`Q6` |
| `msgx.pipeline.backfill-batch` | `100` | 条 | 假定 | 回填扫描单批条数 |
| `msgx.pipeline.backfill-max-attempts` | `100` | 次 | **改作告警阈值** | **不再是放弃判据**:暂时性故障按 `R` 超期放弃(见 design「回填」)。该键保留为单行重试的告警阈值 `[G-BACKFILL-ABANDON-BYTIME]` |
| `msgx.pipeline.backfill-backoff-ms` | 目标参数(未实现) | ms / 档 | 假定 | 回填独立退避表;**当前不存在,回填沿用 `backoff-ms`** `[G-BACKFILL-BACKOFF]` |
| `msgx.pipeline.backfill-backoff-cap-ms` | 目标参数(未实现) | ms | 假定 | 回填退避封顶;旧文档「封顶 15 分钟」无对应配置键,已作废 `[G-BACKFILL-BACKOFF]` |
| `msgx.pipeline.cutover-watermark` | 不设置 | `min\|zero\|max\|<id>` | 一次性运维决策 | 显式播种水位;非法值由启动自检挡下;升级实例拒绝重新播种 |
| `msgx.pipeline.late-detect-period` | `60s` | Duration | 假定 | 只读迟到检测周期;`≤0` 关闭;机制为临时观测(见 design 扫描路径) |
| `msgx.pipeline.late-detect-batch` | `200` | 条 | 假定 | 每轮复查的空洞 ID 上限 |
| `msgx.pipeline.delivery-batch` | `200` | 条 | 假定 | `KAFKA:msg` 每轮每目标领取上限 |
| `msgx.pipeline.delivery-drain-rounds` | `10` | 轮 | 假定 | 连取批数上限,让出循环跑 `schd` flush,防状态通知被积压饿死 |
| `msgx.pipeline.autostart` | `false` | 布尔 | 安全默认 | 启动即拉起收报 / 主泵 / 投递循环;需真实仓储或 `msgx.stubs=true` |
| `msgx.pipeline.event-retention` | 目标参数(未实现) | Duration | 假定 | 已 `SENT` 事件行保留期,由维护作业清理;缺失则 outbox 无限增长 `[G-EVENT-RETENTION]` |
### 1.2 其它 `msgx.*`
| 参数 | 默认 | 依据 | 说明 |
|---|---|---|---|
| `msgx.service-name` | `msgexchangeapi` | 契约冻结 | 服务注册名;影子实例用独立名 |
| `msgx.register-eureka` | `true` | 现役 | 服务注册开关;影子对拍期置 `false` |
| `msgx.stubs` | `true`dev profile | 安全默认 | 内存适配器;**生产禁止**,生产 profile 不设置该键 |
| `msgx.schd.flush-period` | `3s` | 现役 | `schd` 聚合周期 |
| `msgx.schd.flush-limit` | `500` | 假定 | 聚合批上限 |
| `msgx.operation-day.zone` | `Asia/Shanghai` | 现役 | 运营日推导时区 |
| `msgx.operation-day.cutoff-hour` | `0` | **假定(占位)** | 切日边界;待业务确认 |
| `msgx.identity.include-day-boundary` | `false` | 安全默认 | 身份是否加日期边界;影响去重语义,不能当调优项切换(`Q11` |
| `msgx.health.backlog-cache-ttl-ms` | `30000` | 假定 | 积压快照缓存窗口;`0` = 不缓存;`/health``/metrics` 共用同一快照 |
| `msgx.history.history-store-enabled` | `false` | 安全默认 | 历史存储门控;关闭时历史清理删 0 条 |
| `msgx.history.cancelled-hours` | `48` | 假定 | 历史清理的取消态判据窗口 |
| `msgx.history.terminal-hours` | `48` | 假定 | 历史清理的终态判据窗口 |
| `msgx.history.deleted-hours` | `48` | 假定 | 历史清理的已删除判据窗口 |
| `msgx.history.idle-hours` | `168` | 假定 | 历史清理的静默期判据 |
| `msgx.history.snap-log-retention-days` | `90` | 假定 | `SCHD_SNAP_LOG` 保留天数 |
### 1.3 信箱与外部依赖(成组登记)
| 参数组 | 默认 | 依据 | 说明 |
|---|---|---|---|
| `mailbox.processed-value` | `PROCESSED` | 契约(`C-5``Q7`) | 处理标记写入值;仅限库方认可值集 |
| `mailbox.shared-mysql.enabled` | `false` | 安全默认 | 真实信箱接线门控 |
| `mailbox.shared-mysql.connect-timeout-ms` / `socket-timeout-ms` | `3000` / `30000` | 假定 | 有界外部调用;Connector/J 默认无限等待,必须显式 |
| `mailbox.shared-mysql.pool-connection-timeout-ms` / `pool-validation-timeout-ms` | `5000` / `3000` | 假定 | 池级超时 |
| `mailbox.shared-mysql.url` / `username` / `password` | 环境变量 | 安全 | 零入库,见 `.env.example` |
| `datasources.default.connection-timeout` / `validation-timeout` / `idle-timeout` / `max-lifetime` | `5000` / `3000` / `300000` / `1800000` | 假定 | 自有 PG 池(毫秒数,非 Duration 字面量) |
| `datasources.default.data-source-properties.connectTimeout` / `socketTimeout` | `3` / `30` | 假定 | 驱动级超时(秒),防网络黑洞 |
| `kafka.producers.default.acks` | `all` | 契约(architecture D3 | 允许环境变量覆盖 |
| `kafka.producers.default.enable-idempotence` | `true` | 契约(D3) | 允许环境变量覆盖 |
| `kafka.producers.default.max-in-flight-requests-per-connection` | `5` | **与 D3 不一致** | D3 要求 `1`;切流前必须收敛 `[G-KAFKA-D3]` |
环境变量清单以 `.env.example` 为准。
## 2. 指标与健康
| 指标 | 含义 | 期望方向 |
|---|---|---|
| `msgx.pipeline.backlog.unfinished` | 未处理完的消息条数 | 长期 > 0 且不降 → 积压 |
| `msgx.pipeline.backlog.oldest_unprocessed_seconds` | 最老未处理消息的信龄 | 持续增长 → 队头卡住 |
| `msgx.pipeline.backfill.unmarked_terminal` | 已终态但未打标的条数 | 不降 → 回填失败 |
| `msgx.pipeline.backfill.abandoned` | 已放弃自动回填的条数 | **非 0 需人工对账** |
| `msgx.pipeline.backfill.oldest_unmarked_seconds` | 最老待回填年龄 | 决定实际回填延迟 |
| `msgx.pipeline.watermark.lag` | 水位落后信箱最新 ID 的距离 | 增长 → 收报停滞 |
| `msgx.pipeline.hole.aged_out.total` | 永久空洞放行次数 | 突增 → ID 序列大量空位 |
| `msgx.pipeline.late_arrival.detected.total` | 迟到到达命中数 | **> 0 表示上游提交确实晚于水位推进,需要与库方对契约** |
取数规则:统一走 `BacklogSnapshotProvider``PARAM:msgx.health.backlog-cache-ttl-ms`),`/health``/metrics` 共用同一快照——`backlog()``PROC_STATE` 的全表聚合,不能被高频抓取打穿;**无法取数上报 `NaN`,无可比记录的年龄/滞后类仪表上报 `-1`,都不伪造 0**。日志出口故障不得阻塞业务线程。
作业健康:回填扫描的存活性与延迟需要独立可观测(作业心跳、扫描积压、实际回填延迟),因为回填的唯一驱动是扫描作业 `[G-JOB-HEARTBEAT]`
## 3. 模块入口
| 关注点 | 主要入口 |
|---|---|
| 收报与兼容接口 | `ingress/InboxPoller.kt``InboxService.kt``InboxController.kt` |
| 解码 | `codec/JacksonXmlCodec.kt``SisWireMapper.kt``SisMessageBody.kt` |
| 调度与处理 | `processing/Pump.kt`(含 `MessageProcessor`)、`DynamicProcessors.kt`FLOP/FDEL/ADFT)、`Identity.kt` |
| 日计划 | `processing/ScheduleProcessor.kt`;请求协调尚无实现(`REQ_TRACK` 仓储见 `infra/persistence/` |
| 回填与投递作业 | `processing/BackfillService.kt``jobs/JobRunner.kt``HistorySweepJob.kt``delivery/Dispatcher.kt` |
| 持久化与恢复 | `infra/persistence/``infra/retry/``ProcFailure` / `ReplayService` / `FailureScheduler` |
| 启停与配置 | `PipelineLifecycle.kt``config/PipelineProps.kt``config/HistoryProps.kt` |
| 指标与健康 | `infra/metrics/PipelineMetrics.kt``infra/health/BacklogSnapshotProvider.kt` |
| 迁移 | `src/main/resources/db/migration/`(V1 基线、V2 生命周期、V3 HOL 起点、V4 回填闭环、V5 切流播种;`oracle11g/` 为占位) |
## 4. 错误分类与重放白名单
| 错误类别 | 触发 | 处置 | 可重放 |
|---|---|---|---|
| `MALFORMED` | 报文非法或原文缺失 | 立即 `DEAD` | 否 |
| `PROTOCOL` | 整包协议拒绝(运营日冲突、声明数不符、缺载荷) | 立即 `DEAD`,整包不落地 | 否 |
| `CODEC_ERROR` | 解码能力问题 | `FAILED` 退避 | 是 |
| `UNSUPPORTED` | 处理器或快照能力未实现 | `FAILED` 退避,受尝试上限约束 | 是 |
| `INFRA` | 基础设施或执行异常 | `FAILED` 退避 | 是 |
| `EXHAUSTED` | 尝试次数耗尽 | `DEAD``ERROR_CLASS` 被覆写为 `EXHAUSTED`(原始类别不保留,`LAST_ERROR` 留文本) | 是 |
回填放弃原因:`MISSING_ROW`(信箱行不存在,确定性结论)、`TRANSIENT_DEADLINE`(暂时性故障持续到 `R` 仍未打标)。两者都不写 `BACKFILL_AT`,都不等于标记已确认;`R` 之前不放弃。