Files
baiyue-firstleg/docs/同步调用依赖与失败传播治理基线.md

152 lines
14 KiB
Markdown
Raw Permalink 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.
# 同步调用依赖与失败传播治理基线
## 目的与口径
本基线覆盖当前官方 22 个 Maven 模块、15 个可执行服务之间的 OpenFeign、`RestClient`、`WebClient` 与 JDK `HttpClient` 调用。海外安全 Inbox/投影属于 Lastleg 内部子域,不再作为独立服务节点。基线用于识别同步依赖方向、在线请求深度、后台中继、超时、重试、熔断、幂等、错误映射和失败传播,不改变 Finance 或海外仓业务业务状态机。
“存在双向服务边”不等于“一次在线请求会递归调用”。每条边必须继续区分:
- `REQUEST`:用户或设备请求线程内,失败直接影响当前业务结果;
- `BACKGROUND`:Outbox、Inbox、定时器或导出 Worker 中的同步传输,业务事务已与传输解耦;
- `INFRASTRUCTURE`:审计、网关会话校验等基础设施调用;
- `EXTERNAL`:Integration 对第三方供应商的调用。
逐客户端可执行清单位于 `scripts/synchronous-dependency-baseline.mjs`,离线合同为 `scripts/synchronous-dependency-contract.test.mjs`。清单逐项冻结 44 个 Feign 与 16 个原始 HTTP 客户端的执行上下文、`READ/WRITE/READ_WRITE`、幂等类型和说明,并从同一事实源输出 REQUEST、BACKGROUND、INFRASTRUCTURE、EXTERNAL 与全图。新增客户端、目标服务、在线边、强连通分量或超时配置时,必须先更新基线并完成调用方与被调用方评审,不能仅修改测试期望以放行。
## 当前服务边
### OpenFeign
| 调用方 | 被调用方 | 客户端数 | 主要上下文 |
|---|---|---:|---|
| Auth | IAM | 2 | 登录授权、注册,`REQUEST` |
| IAM | Auth | 1 | 账号开通/管理,`REQUEST` |
| IAM | Firstleg | 1 | 客户尺寸默认规则可靠任务投递,`BACKGROUND` |
| IAM | Warehouse | 1 | 海外仓储费协作,`REQUEST` |
| IAM | Event Bridge | 1 | 安全事件中继,`BACKGROUND` |
| Order | Firstleg | 3 | 计价/统一订单查询为 `REQUEST`,入库协作为 Outbox `BACKGROUND` |
| Order | IAM / File / Warehouse | 各 1 | 资格、图片、仓库守卫,`REQUEST` |
| Firstleg | Order | 2 | 货物查询同时存在 `REQUEST/BACKGROUND`;PDA 履约分拆为 `REQUEST` |
| Firstleg | IAM / Finance / Integration / Event Bridge / Print | 各 1 | IAM、Integration、Print 为 `REQUEST`;Finance 与 Event Bridge 为 `BACKGROUND` 中继 |
| Firstleg | File | 7 | 测量、装柜、凭证、报关、拖车等,`REQUEST` |
| Firstleg | Warehouse | 4 | 主数据、供应商、库位/托盘,`REQUEST` |
| Finance | Firstleg | 2 | 费用来源/成本快照,事件消费与平台操作混合 |
| Finance | File / IAM / Warehouse | 各 1 | 凭证、客户、供应商校验,`REQUEST` |
| File | IAM | 2 | 资质登记为 `REQUEST`;导出 Provider 为 `BACKGROUND` |
| File | Order / Firstleg / Finance / Warehouse | 各 1 | 导出 Provider,`BACKGROUND` |
| File | Integration | 1 | OCR 在上传处理请求线程执行,`REQUEST` |
| Lastleg | Event Bridge | 1 | 跨区事件 Outbox 中继,`BACKGROUND` |
| Lastleg | 国内 Warehouse | 1 | 合作仓报价快照,`REQUEST` |
合计 44 个 Feign 客户端。公共默认连接/读取超时为 3 秒/5 秒;File 的五个导出 Provider 客户端读取超时单独为 15 秒。
### 原始 HTTP
| 调用方 | 被调用方 | 实现 | 上下文与当前策略 |
|---|---|---|---|
| Gateway Overseas | Auth | `HttpPdaSessionValidationClient` | `INFRASTRUCTURE`;总超时 2 秒,异常由网关失败关闭 |
| Gateway Overseas | Lastleg Security 子域 | `HttpOverseasSecurityValidationClient` | `INFRASTRUCTURE`;Lastleg 内部安全投影实时校验,异常失败关闭,不进入在线业务图 |
| Lastleg | Warehouse Overseas | 两个 `RestClient` Gateway | `REQUEST`;分别使用 3 秒连接、5 秒读取超时,配置可覆盖,不自动重试 |
| Lastleg | File | 两个照片 `RestClient` Gateway | `REQUEST`;分别使用 3 秒连接、30 秒读取超时,配置可覆盖;校验响应 code 且失败关闭,不自动重试 |
| Event Bridge | Firstleg / Lastleg(业务事件与安全投影两个入口) | 三个 JDK `HttpClient` | `BACKGROUND`;连接 3 秒、请求 10 秒,持久化租约和退避由 Event Bridge 专项治理;Lastleg Security 投影不进入在线业务图 |
| 启用 Common Audit 的服务 | Audit | `HttpAuditSink` | `INFRASTRUCTURE`;当前捕获异常后仅告警,可能让调用方误以为审计已成功,是高优先级失败传播缺口 |
| Integration | 外部 OCR/船司 | 六个 JDK `HttpClient` | `EXTERNAL`;OCR 默认 10/60 秒,船司默认 10/30 秒,业务重试必须服从供应商和调度契约 |
#### Lastleg 四个有界 RestClient
六个客户端统一从 `LastlegRestClientFactory` 构建 JDK HTTP 传输,由 `LastlegRestClientProperties` 绑定独立超时。读取超时是单次请求的硬边界;客户端没有 Retry、fallback 或默认成功配置。
| 客户端 | 构建与调用路径 | 写操作幂等性 | 默认超时 |
|---|---|---|---|
| `HttpUnloadPhotoFileGateway` | `ReceivingContainerController → ReceivingContainerService → UnloadPhotoFileGateway → /internal/file/v1/business-files/**` | `validate` GET 可重复;`upload` 每次写文件和元数据,没有幂等键,禁止自动重试 | 连接 3 秒、读取 30 秒 |
| `HttpRelabelPhotoFileGateway` | `RelabelPdaController/Service → RelabelPhotoFileGateway → /internal/file/v1/business-files/**` | `validate` GET 可重复;`upload` 没有幂等键,禁止自动重试 | 连接 3 秒、读取 30 秒 |
| `HttpCustomerVisitFileGateway` | `CustomerVisitService → CustomerVisitFileGateway → /internal/file/v1/business-files/**` | 附件上传没有幂等键,禁止自动重试;元数据读取可重复 | 连接 3 秒、读取 30 秒 |
| `HttpProcurementFileGateway` | `OverseasProcurementService → ProcurementFileGateway → /internal/file/v1/business-files/**` | 采购凭证和签收文件上传没有幂等键,禁止自动重试 | 连接 3 秒、读取 30 秒 |
| `HttpWarehouseResourceGateway` | `InboundPdaWorkflowService`、PDA 仓内查询/盘点及 Dropship → Warehouse Resource/Pallet 内部接口 | 查询可重复;`reserve` 使用 `reservationKey`,`ensureDropship` 使用业务绑定,release/scrap 由服务端状态收敛;尽管服务端具备业务幂等,客户端仍不自动重试 | 连接 3 秒、读取 5 秒 |
| `HttpPalletPhysicalGateway` | `PdaPalletOperationService`、`PdaInventoryMoveService` → `/internal/v1/pda-pallet-transitions/**` | 查询可重复;apply/compensate 使用稳定 `operationKey` 与请求哈希,服务端幂等;客户端仍不自动重试 | 连接 3 秒、读取 5 秒 |
## 分上下文依赖图
### 在线 REQUEST 图
在线图只包含用户或设备请求线程中实际执行的服务边。Event Bridge、Outbox、船节点定时任务、导出 Provider 和 Gateway→Lastleg Security 基础设施校验均不计入在线深度。
当前在线强连通分量为:
`Auth ↔ IAM`;`Firstleg ↔ Order`
`IAM → Firstleg` 默认尺寸初始化已退出请求线程,合同现冻结 21 条在线服务边;新增在线边或新增强连通分量直接失败。File 不再属于在线强连通分量;Finance、Lastleg 只指向上述分量或叶子服务,不属于在线环;Gateway Overseas→Lastleg Security 是 `INFRASTRUCTURE`,不是 REQUEST 边。
### 后台 BACKGROUND 图
后台图包含 Outbox/Inbox、导出 Worker 和定时任务,当前强连通分量为:
`Event Bridge ↔ Firstleg ↔ Finance ↔ Lastleg ↔ Order`
File 的五个导出 Provider、Order→Firstleg 入库 Outbox、该入库消费者为生成箱号而回读 Order 货物的后台回调、IAM 默认尺寸可靠任务、IAM 安全 Outbox、Firstleg/Lastleg 跨区 Outbox、Firstleg→Finance 费用 Outbox及 Event Bridge 三个消费者均只在后台图中计算。Event Bridge→Lastleg Security 与 Event Bridge→Lastleg 业务事件在服务图上收敛为同一条后台服务边,不形成新的在线业务边或独立安全节点。
### 全图
全上下文合并后,非平凡强连通分量仍为 8 个服务:
`Auth ↔ IAM ↔ Order ↔ Firstleg ↔ Finance ↔ File ↔ Event Bridge ↔ Lastleg`
全图只用于部署影响和故障域观察,不能再用于推导在线调用“无限深度”。
### 用户入口在线最长简单路径
默认在线预算为最多 2 个下游服务跳数。合同对每个已知用户入口枚举全部最长简单路径;下表列出的具体路径均超过预算:
| 用户入口 | 最长跳数 | 全部长路径 |
|---|---:|---|
| 订单 API | 4 | `Order → Firstleg → File → IAM → Auth`;`Order → Firstleg → File → IAM → Warehouse` |
| 头程 API/PDA | 4 | `Firstleg → Order → File → IAM → Auth`;`Firstleg → Order → File → IAM → Warehouse` |
| 财务 API | 5 | `Finance → Firstleg → Order → File → IAM → Auth`;`Finance → Firstleg → Order → File → IAM → Warehouse` |
| 海外尾程 API/PDA | 3 | `Lastleg → File → IAM → Auth`;`Lastleg → File → IAM → Warehouse` |
这些是静态服务边可形成的最长简单路径,不表示每个具体 Controller 都会走完整链;后续入口级调用点治理必须继续以实际 Service 调用证据缩小路径,不能用静态可能性宣称线上已经发生。
### 已完成的第一个 REQUEST 边退出
`IAM → Firstleg` 的 `CustomerDimensionRuleClient` 默认尺寸初始化已经从 REQUEST WRITE 改为可靠后台编排。IAM 与客户主档同事务持久化稳定 `initializationKey` 的任务,显式维护 `PENDING/READY/FAILED`,由租约调度重试并提供诊断查询和人工重试;审批通过与下单资格在未 READY 时失败关闭。此边现在仅属于 BACKGROUND,在线五服务强连通分量实际拆为 Auth↔IAM 与 Order↔Firstleg 两个子环,未触碰财务、Event Bridge 或海外仓业务业务状态机。
### Order↔Firstleg 第二阶段结论
具体入口、所有权与可执行退出方案见 `docs/Order-Firstleg在线依赖解环设计.md`。当前 `COMPLETE_LOADING` 在 Firstleg 本地事务中同步取得 Order 余量子单后才完成结算,且 Order 货物在 `LOADED` 前仍允许修改;成功时点和货物冻结点尚未冻结,因此本阶段不改业务代码。REQUEST SCC 仍为 `Firstleg↔Order`,合同明确阻止仅改变分类却未退出生产调用的伪解环。
## 退出顺序
1. **冻结与分层。** 先用清单合同阻止未评审新边;为每个客户端补齐 `REQUEST/BACKGROUND/INFRASTRUCTURE/EXTERNAL`、读写语义、幂等键和失败映射。这个阶段不改变业务状态。
2. **统一失败传播与时间预算。** 为 Feign 和原始 HTTP 明确连接/读取/总超时;默认禁用自动重试,只有具备幂等键且由业务明确拥有退避状态的后台操作可以重试;禁止空数据、默认成功或仅日志告警替代远端失败。
3. **先退出伪在线环。** File 导出 Provider、Firstleg/Lastleg Event Bridge、Firstleg→Finance 费用投递继续作为后台链路,但必须从在线深度图剥离,并禁止 Worker 消费时无界同步回调。
4. **退出 `Order ↔ Firstleg` 在线双向命令。** 保留一个方向的权威查询,将反向状态推进改为带版本、幂等和审计的 Outbox/Inbox;不复制 Order 交易状态或 Firstleg 履约状态。
5. **退出 `Auth ↔ IAM` 在线双向写。** Auth 保持账号与 Token 唯一所有者,IAM 保持客户/RBAC 所有者;注册和账号开通使用可恢复编排,登录授权快照失败关闭,不引入第二套账号事实。
6. **收敛 `IAM ↔ Firstleg`。** 客户维度规则和客户快照确定单一事实方向;允许短期只读查询,禁止两个服务互相修正对方数据。
7. **在财务总控确认后退出 `Firstleg ↔ Finance` 回调。** 优先让版本化事件携带 Finance 校验所需的不可变快照或使用单向快照读取,保持 Finance 状态机和 Firstleg 费用事实边界不变。
8. **收敛 File 相关环。** File 只拥有文件对象与导出任务;业务服务拥有导出数据和业务归属。凭证/照片校验失败关闭,导出 Worker 使用受限批次、超时和显式失败状态。
## 错误、重试与熔断基线
- 远端 HTTP 非 2xx、响应体 `code != "200"`、空响应和 DTO 不完整是四类不同失败,均不得变成成功或空列表。
- 在线查询/命令默认不自动重试。若启用重试,必须同时证明方法幂等、请求具有稳定幂等键、最大尝试次数和总时间预算可控。
- Outbox/Inbox 重试由持久化状态拥有,Feign/JDK 客户端不得再叠加隐式重试造成次数乘法。
- 熔断打开时返回统一“依赖不可用”错误并保留 request/trace 关联信息,不配置业务成功型 fallback。
- 404 只有在契约明确“资源不存在”时可映射为领域未找到;连接失败、超时、5xx、空响应必须映射为依赖不可用。
- Common Audit 当前“只记录告警后返回”列为已知例外,不能据此推广静默降级;其可靠性与业务阻断口径需和审计/总控共同冻结。
## 直接受影响验证
| 变更范围 | 最低验证 |
|---|---|
| 图、客户端或超时配置 | `node --test scripts/synchronous-dependency-contract.test.mjs` |
| 单个 Feign/HTTP 签名或错误映射 | `mvn -pl <调用方>,<被调用方> -am test-compile`,并运行双方直接相关测试 |
| Auth/IAM | `mvn -pl auth,iam -am test` |
| Order/Firstleg | `mvn -pl order,firstleg -am test` |
| IAM/Firstleg | `mvn -pl iam,firstleg -am test` |
| Firstleg/Finance | `mvn -pl firstleg,finance -am test`;业务口径先由财务总控确认 |
| Firstleg/File 或 File/Finance | `mvn -pl firstleg,file,finance -am test`,按实际消费者缩小模块集 |
| Lastleg 原始 HTTP | `mvn -pl lastleg-service,warehouse-overseas-service,file -am test`;不改变海外仓业务状态机 |
| 全部治理阶段收口 | `mvn -DskipTests validate` 后执行 `mvn test` |
以上均为本地离线验证;未经明确授权不启动 Java/Nacos/数据库,不执行 SQL、部署或测试环境 HTTP 验收。