KEEL · 龙骨 · A CURRICULUM FOR THE AI ERA
07. 超时以后,最重要的是承认“不知道” — keel 龙骨
客户端调用配置服务,等待 10 秒后超时。以下三种事实都会产生同一个客户端现象:
客户端调用配置服务,等待 10 秒后超时。以下三种事实都会产生同一个客户端现象:
- 请求根本没有到达服务端;
- 请求到达,但服务端在提交前失败;
- 服务端已经提交,成功响应没有返回。
因此 timeout 描述的是观察结果,不是业务结果。
Failure 和 Unknown 的区别
failed 已有权威证据表明动作没有完成
unknown 当前证据不足,动作可能完成也可能没有完成
把 unknown 写成 failed 会诱导重试;写成 succeeded 会制造假事实。正确做法是保存未知状态和可查询线索。
对账从读取事实开始
配置动作可以按资源和期望值查询:
本地 Command: set pool_limit=40, expected version=cfg-7
外部现状: pool_limit=40, version=cfg-8, change_id=command-123
判断: 本动作已生效 -> succeeded
仅比较最终值有时不够。另一个操作者也可能把值改成 40,所以外部系统最好保存 command_id、幂等键或变更事件 ID。
Reconciler 的三种结论
flowchart TD
U[unknown receipt] --> Q[按 external_reference / resource 查询]
Q -->|找到同一 command 的成功记录| S[succeeded]
Q -->|明确未提交且可安全重试| F[failed / retryable]
Q -->|证据冲突或不可查询| M[manual_review]
对账器不重新执行动作。它只读取权威系统并更新本地认识。
Read-your-own-writes 也可能暂时失效
外部系统采用最终一致性时,刚提交的写入可能尚未出现在读副本。一次查不到不能立刻断言未生效。对账策略需要:
- 明确权威读取端点;
- 在 deadline 内按退避窗口复查;
- 记录每次查询的时间和证据;
- 超过判断能力时转人工,不无限等待。
运行未知结果实验
python courses/advanced/real-world-execution/course/project/examples/06_unknown_and_reconcile.py
模拟 Adapter 在提交后丢失响应。Gateway 首先记录 unknown;Reconciler 随后按 command ID 查到外部变更记录,才把状态改成 succeeded。配置不能被执行第二次。
检查理解
- 为什么 timeout 不能直接映射成 failed?
- 只比较资源最终值,为什么可能把别人的动作认成自己的?
- Reconciler 为什么不应该顺便重放命令?