外观
第 18 章 Chapter Outline:Retry、Recovery 与容错
章节契约
读者完成后的能力: 能将失败拆为可重试、需观察、需补偿、不可恢复或需人工升级的条件;能为一次尝试写出效果状态、上限、检查点和停止条件;能解释为什么“超时”“失败”和“未执行”不是同义词;能审查一个恢复策略是否会重复副作用或放大负载。
前置知识: 第 10、11、14、15、17 章。读者只需能理解 JavaScript 对象、状态表和 Mermaid 状态图。
章节边界: 不证明真实 Tool、HTTP、队列、浏览器、云服务或数据库动作是否可重试;不实现睡眠、指数退避、熔断器、恢复执行或补偿执行;不把教学输出当作真实故障处理结果。
小节蓝图
1. 失败不是一个状态:从失败文本到恢复决定
- 读者问题: 为什么
timeout、permission_denied、invalid_input和效果未知不能走同一条“重试”路径? - 叙述任务: 分开失败信号、效果状态、证据缺口和下一步决策。
- 来源边界: 分类表是本书模型;REF-065 仅提供通信失败和幂等请求重试的协议语境。
- 验证: 读者能指出“未读取到响应”不是“服务端没有执行”。
2. 有条件的重试:预算、上限、退避与单一所有者
- 读者问题: 什么条件下可再发一次尝试,又如何避免一层层放大?
- 叙述任务: 介绍可重复性、上限、重试预算、退避/随机化和单层所有者;把具体参数放到任务契约。
- 来源边界: REF-066 只支持 Google SRE 的负载放大风险与建议;
Recovery Contract为本书模型。 - 验证: 读者能拒绝“多层各重试三次”的无主策略。
3. 先观察还是先恢复:效果状态与检查点
- 读者问题: 调用中断后,为什么不能默认重新执行?
- 叙述任务: 使用
not_applied、applied、unknown;说明检查点保存的不是成功文本,而是可恢复所需的关联、状态、输入摘要和补偿信息。 - 来源边界: 观察和状态术语沿用第 10、11、15 章;字段为本书模型。
- 验证:
unknown进入needs_observation或escalate,不进入自动重试。
4. 恢复与补偿:修复有效状态,而非承诺回到过去
- 读者问题: 已部分完成的多步骤任务如何选择恢复、补偿还是保留状态?
- 叙述任务: 定义恢复 Runbook、补偿触发、不可逆点和人工决定。
- 来源边界: REF-067 仅提供补偿事务的应用特定、可失败、需关联/进度/人工的背景。
- 验证: 读者能解释为何“撤销”要有自己的幂等性与检查点。
5. 停止、熔断与人工升级:给失败留出口
- 读者问题: 何时停止比继续尝试更可靠?
- 叙述任务: 定义重试耗尽、不可重试错误、不可逆效果、证据缺口和补偿失败的出口;说明熔断是运行时策略,不是一个布尔值。
- 来源边界: 停止/升级矩阵为本书模型;不实现真实断路器。
- 验证: 读者能为每个出口说明需记录的证据和人类所需的下一步。
6. 完整工程案例:资料获取失败的受限研究 Agent
- 读者问题: 如何在资料下载不稳定时避免编造内容或无限刷新?
- 叙述任务: 构造教学场景:只读资料获取先检查来源、再在受限策略内重试;效果未知时观察;多次失败记录阻塞并交接;已写入的错误摘要只能在存在补偿契约时处理。
- 来源边界: 文件名、来源、状态和结果均为教学对象,不表示网络请求或内容获取已发生。
- 验证: 纯内存测试覆盖可重试、未知效果、补偿、缺检查点、不可逆和升级。
计划图示与示例
- 图示: 失败分类先检查效果状态,再根据策略、上限、检查点和补偿能力输出
retry、recover、compensate、needs_observation、stop或escalate。所有节点都只表示本书教学决策。 - 示例:
assessRecoveryDecision对注入的操作、失败、检查点和策略做确定性判定;它不等待、不重试、不写日志、不执行补偿或调用外部系统。
Outline 完成检查
- [x] 覆盖错误分类、退避/预算、幂等性、检查点、补偿、停止和人工升级。
- [x] 已将观察、评估和长期运行章节的责任分开。
- [x] 已明确来源事实、本书模型和教学案例的边界。
- [x] 已定义可观察的图示、代码与测试路径。
