一项能力能否长期维护,不取决于演示是否成功,而取决于团队能否解释每个状态、每次重试和每一份残留数据。 Saga 已提交的步骤不能被 ACID 回滚,只能执行新的补偿业务动作。每个步骤保存状态和补偿幂等键,取消请求与正在完成的步骤通过状态机仲裁。
分布式正确性来自幂等键、租约、单调版本和可对账事实,而不是假设请求只到一次。超时代表结果未知,调用方不能未经确认就把它解释成失败。
设计时必须回答的问题
这项能力横跨客户端、网络与服务端,局部最优很容易制造全局故障。工程决策需要同时约束两端行为、持久化事实和运维预算。
- 将步骤分为可撤销、可补偿和不可逆;收到取消后停止安排新步骤,等待在途结果,再按逆序补偿并记录残留。
- 为状态写出唯一所有者、版本号和终态;任何回调只能修改自己创建的版本。
- 兼容性通过显式能力协商决定,旧客户端得到可解释的降级路径,而不是进入半可用状态。
“长流程取消语义:Saga 补偿不是数据库回滚”的交付标准是正常路径可用、异常路径收敛、资源有界,并且用户能理解系统为何采用当前状态。 这样得到的不是演示代码,而是能解释、能降级、能回滚的生产能力。
边界情况不是附加项
生产问题往往发生在两个正确动作同时到达时。需要逐条检查迟到消息、重复执行、资源耗尽和版本交叉,而不是只补当前堆栈显示的那一行。
- 取消与完成同时发生时双方各自显示不同终态;补偿失败若被当作已取消,会留下配额、临时对象或通知无法追踪。
- 只修正界面状态而没有清理底层资源,下一次操作继承队列、锁或过期凭据并再次失败。
- 降级路径从未压测,主路径故障时所有流量同时进入更慢、更昂贵的后备方案。
用证据确认它真的可用
发布闸门应包含确定性回归、随机时序探索和真实浏览器组合。发现一次失败后保存 seed 与状态轨迹,让它永久成为可重放用例。
- 在每个步骤提交前后注入取消和崩溃,重复执行补偿,验证最终状态矩阵、残留清单与用户提示完全一致。
- 用乱序、重复和延迟消息驱动状态机,确认旧版本被丢弃且显式停止不会被自动恢复覆盖。
- 发布前记录成功率、p50/p95/p99 延迟、错误分类和资源高水位,并为回退条件设定明确阈值。
最终交付标准应当是:正常路径足够快,异常路径能够收敛,用户意图不会被自动恢复覆盖,运维人员也能从有限而安全的证据定位问题。