第 15 章:记录足以恢复的事实
一条“调用失败”日志无法回答工具有没有完成业务。一条“任务成功”日志也不能证明状态和审计事件一起提交。长任务的可观察性,首先要为恢复判断提供证据,再帮助人理解延迟和失败,不能只是堆积更多自然语言。
15.1 分清状态、事件和工具账本
工作流行保存当前状态、计划、审批有效期、owner、fence、尝试预算和结果。事件表记录执行过程中已经提交的转移。工具账本保存副作用提供者的业务事实。三者能够互相解释,但没有任何一个单独拥有全部答案。
看到 running,只能说明最近一次领取尚未结束,不能据此断言请求仍在网络中。看到 unknown,也不能断言工具失败。只有经过验证的工具回执,才能支持“这个操作键对应的效果已经存在”。反过来,工作流本地 succeeded 的可信度,还取决于保存它之前是否验证过回执。
程序输出是额外观察渠道。进程可能在提交后、写日志前退出,因此日志缺失不等于事务没有提交。重建事实时应以持久记录和权威查询为基础,再用日志解释时间线,而不是依赖一条可能来不及刷出的消息。
15.2 状态和事件必须一起成功
Complete 在一个本地事务里更新工作流并插入 completed 事件。TestTerminalTransactionRollsBackButEffectCanBeReconciled 给事件表添加拒绝 completed 的 CHECK 约束,强迫事件写入失败。
这个故障发生之前,真实 HTTP 工具已经在自己的事务里提交。随后本地终态事务回滚,测试读取 SQL,看到工作流仍为 running、result 为空,completed 事件数量为零,而工具账本已有一行。观察值为:
{"after_rollback":"running","result_rolled_back":true,
"completed_events":0,"effects":1,"post_calls":1,
"after_reconcile":"succeeded"}最后一个字段来自移除约束、显式注入租约过期,再执行核查之后。这里没有回滚工具效果;本地事务的原子性不能跨越 HTTP 提供者的独立提交。正确的恢复是承认工具事实,再以一笔新的本地事务保存它。
15.3 结构化观察要说明证据来源
每个实验用 t.Log 输出 BOOK_OBSERVATION 加 JSON。CI 保存原始 go test -json 流,再提取这些对象,附上测试名、源码提交、实际 Go 和 PostgreSQL 版本、镜像摘要。读者可以从汇总回到原始输出,检查某个结论究竟来自哪项实验。
自然到期的 SIGKILL 实验记录 lease_expiry 为 PostgreSQL 时钟下真实三秒租约;其他精确时序实验记录 SQL 注入。两者能回答不同问题:前者覆盖真实等待与跨进程恢复,后者稳定触发某个边界条件。混写成“全部真实等待”会扩大证据含义。
机器汇总保留测试的 pass、fail 和 skip,不把 skip 当作成功。缺少数据库时,本地 Go 测试会明确跳过集成部分;出版验收的收集器检查声明的测试是否全部出现,并拒绝跳过或失败。这样“编译通过”不会被误写成“恢复实验通过”。
15.4 事件不应复制全部输入
账户、凭据、模型原文和 HTTP 请求体若被反复复制到事件,会扩大数据暴露与删除成本。实验事件只写受控的转移类型和少量说明,不复制账户字符串、工具令牌或业务 JSON。TestEventsExcludeRawSensitiveInputs 使用一个带明显标记的账户运行完整任务,再逐条查询 kind 和 detail。
真实结果检查了四条事件,未发现选定的敏感原文标记。这是有范围的测试:它覆盖事件的这两个字段,不等于所有日志、数据库备份和遥测都已脱敏。工作流计划和工具账本仍有账户与数量,因为它们保存业务执行所需事实。
在生产系统中,需要分别决定业务记录、审计事件、调试日志的访问权限与保留期限。若为了关联而使用散列值,还要考虑低熵字段是否容易枚举。把账号做一次无密钥散列,并不会自动满足隐私需求。
15.5 指标应推动可执行处置
队列数量能够显示积压,但队列年龄更接近用户等待。unknown 数量显示待核查规模,unknown 停留时间说明处置是否失速。租约回收速率上升可能来自进程故障,也可能来自心跳连接被挤占,需要结合连接池、数据库延迟和工具延迟分析。
重试指标还应区分可信前置拒绝、传输错误、回执不匹配和人工待核查。把它们混成一个错误率,会鼓励系统对所有错误使用同一重试策略。尤其不能为了让失败曲线下降,把 unknown 批量改成 failed 或 ready。
告警需要对应处置说明。例如 unknown 超龄,值班者先查询权威工具记录,确认键和指纹;版本不兼容,交给版本负责人;持续 429,检查配额和速率;终态事务失败,检查数据库约束或写入可用性。每一种行动都要保存新的证据,避免“人看过了”成为不可复查的终点。
练习。 监控显示工具 POST 错误率升高、unknown 增多,但工具账本的效果数量仍在增长。请写出前三步调查动作,指出哪些事实可以由本地 SQL 确认、哪些必须查询提供者。再选择五个值得长期保存的事件字段,并说明你刻意不保存的敏感内容。