跳转至

02 · 持久执行面试题

工单已经创建,成功响应却没回来,恢复后该再点一次吗?重试要拿着原收据查结果,不能一着急就重新下单。持久执行要说清恢复计算、批准动作和外部事实各由谁负责。

配套 学习章:持久执行,本章覆盖 Q060–Q062,围绕重放窗口、审批与并发接管展开。

Q060 持久执行为什么仍需要外部幂等?

优先级:P0

30–60 秒回答:

持久执行按检查点或已保存任务结果恢复,某些代码仍会重执行。远端写入成功后,如果本地结果尚未保存就退出,恢复无法仅凭检查点判断写入是否发生。需要沿用同一业务意图 ID,结合服务端幂等、结果查询或对账。检查点保存进度,幂等合同处理重复请求,两者不能互相替代。

展开详细答案、追问与案例

详细答案:

先标出重放边界:框架恢复的是已记录的状态和结果,并不恢复原 Python 调用栈。节点可能从开头运行,Functional API 可以从入口重放并取回已持久保存的 task 结果。当前时间、随机数、模型输出和远端响应都会变化,应将这些操作组织到可识别的任务中,保存决策结果,使恢复能解释为何继续同一条路径。

再单独分析外部写入窗口。创建工单已成功,但进程在保存工具结果前退出,任务包装无法把远端事务和本地记录变成一个事务。把“发邮件再写日志”放入一个大任务也存在相同问题。应在首次提交前固定业务意图 ID,并持久保存规范化参数;服务端按其幂等合同识别重复请求,同 ID 不同参数必须进入冲突处理,不能悄悄接受新动作。

最后给结果未知建立显式状态。超时只说明调用者没取得结果,不能直接记失败并换新 ID。优先按原 ID 查询,支持幂等时以相同参数重试,否则对账或等待人工判定。任务拆得更细可以减少重做范围,却会增加状态和版本管理成本;仍要保留操作与结果的对应关系,并在代码升级时维护任务身份、执行顺序和状态含义。

常见追问:

  1. 每次重试生成新 UUID 更安全吗? 新 UUID 会让下游把同一意图当成多次创建。业务 ID 应跨重试稳定,尝试 ID 则可以每次不同,用于诊断具体请求。
  2. 只在本地建去重表够不够? 不够。若先写去重表再调用,可能漏执行;先调用再写表,可能重复。要检查服务端原子记录与变更合同,或用查询和对账覆盖窗口。
  3. 哪些错误应该重试? 限流或暂时不可用可按预算退避;参数、权限和业务冲突需修正条件。写请求超时先进入结果未知分支,不能与明确未执行混为一谈。

实战案例:

报告 v7 获批后,op17 在工单服务创建了 T9,响应却丢失。恢复看到本地“待创建”,初版流程换 ID 再发会产生重复工单。改为先保存 op17 及参数,恢复按 op17 查询并核对 T9,再补写本地状态。验收时分别在提交前、远端成功后和结果保存后注入中断;允许请求发生多次,但同一业务意图只关联一个符合参数的工单,所有尝试都能追踪。

常见误区:

把 durable task 当成跨系统事务;把网络超时当成远端失败;认为有幂等键就不必规定同键不同参数的行为。

微练习:

为“创建工单→保存对象 ID”画四个故障点。验收:每处都写出可确认事实、稳定操作 ID、查询或重试路径;明确指出哪一处不能直接判定成功或失败。

学习与参考: 配套学习章 · LangGraph 重执行 · Functional API 确定性 · AWS 幂等 API

Q061 怎样让审批与 Outbox 在恢复后仍保持正确含义?

优先级:P0

30–60 秒回答:

审批应绑定具体动作版本,包括对象、工具版本、规范化参数、收件人和附件,并独立验证审批人身份与权限。批准后把业务状态和待发送事件写进同一本地事务,再由分发器投递。Outbox 解决本地双写窗口,投递仍可能重复,下游需要幂等。旧批准不能无条件覆盖修改后的报告。

展开详细答案、追问与案例

详细答案:

审批先需要一个可恢复的业务对象,而不只是布尔值。保存请求 ID、申请人、报告版本、动作摘要、参数 hash、有效期和当前状态。摘要应覆盖真正会执行的动作,例如发布到哪个对象、由哪个版本的工具执行、发送哪些附件。Hash 只是绑定内容的方式,不证明谁批准,也不能代替审批人当前权限检查;动作变化后按业务合同重新建立批准关系。

等待阶段将 pending 状态持久化并释放执行资源,恢复收到外部输入后,重新核对请求是否已失效或被新版本替代。Interrupt 提供暂停与恢复机制,权限、过期和版本匹配仍由业务实现。重放还受代码顺序影响,不能随意调整旧运行中的 interrupt 和任务位置;应固定版本或在兼容路径上迁移,避免把一次输入匹配给另一个动作。

批准后若需要同时记录“已排队”和发送事件,可以把业务状态与 outbox 行放入同一数据库事务,提交后再投递。事务未提交,两者都不生效;提交后分发器继续处理。但远端收到消息和本地标记已投递之间仍有窗口,所以事件 ID 必须稳定,消费方按合同去重。这里换取的是明确的本地一致性与可恢复投递,代价是后台分发、积压监控和对账,并没有获得跨系统一次性执行承诺。

常见追问:

  1. 只对正文做 hash 可以吗? 若收件人、附件或目标也影响动作,就必须一起绑定。正文不变但发送对象改变,已经是不同的授权范围。
  2. 为什么 outbox 消息可能重复? 分发器可能在远端成功后丢失确认,或收到确认却来不及保存标记。恢复仍会发送同一事件,下游应返回已有结果。
  3. 旧状态缺少新版必填字段怎么办? 从原请求和可靠记录恢复;例如金额 650 没有币种,无法判断时应补信息。不能随意填默认值并继续使用旧审批。

实战案例:

报告 v7 批准后,用户把附件替换为 v8。初版只保存 approved=true,恢复会发送新附件。处理时建立与 v7 动作摘要绑定的批准记录,将被替代请求标为 superseded;新动作重新走审批,批准后事务写入待发事件。验收时重放旧批准、替换附件、重复投递同一事件,分别确认旧批准不触发新动作、版本变化可追踪、重复投递不生成第二个业务对象。

常见误区:

把暂停等同于审批;把 hash 当作身份凭证;认为 outbox 提交意味着外部工单已经创建,或消费方可以不去重。

微练习:

写出发布动作摘要和审批状态转换,再列出 outbox 的四个故障窗口。验收:正文、收件人、附件任一变化都有明确处理,事件重复到达时可关联同一外部结果。

学习与参考: 配套学习章 · LangGraph Interrupts · 重放确定性 · AWS Transactional Outbox

Q062 租约、Fencing 与取消分别保护什么?

优先级:P1

30–60 秒回答:

租约帮助分配一段时间内的执行权,Fencing 由受保护资源拒绝陈旧执行者,幂等处理同一意图的重复请求。取消则先持久保存停止意图并阻止新的业务动作调度,已发出的远端动作还要对账。旧进程可能在租约过期后恢复,所以只在协调者里检查租约,不能自动保护真正的写入。

展开详细答案、追问与案例

详细答案:

长任务可能因进程暂停、网络分区或调度超时而交接。租约到期让新工作进程获得执行权,却不会物理删除旧进程已经持有的内存和连接。旧进程苏醒后仍可能提交动作,因此执行权分配与写入保护必须分开设计。给每次接管发放递增令牌,并让资源保存已见令牌、拒绝更旧值,才构成 fencing 的关键机制。

例如 A 持有 41 后暂停,B 取得 42 并完成受保护写入。A 再带 41 提交时,资源应拒绝它。这个保证依赖资源实际检查,而不是请求里多一个字段;也不能把“租约刚过期”直接等同于“资源已经见过新令牌”。外部服务不支持令牌时,若采用网关,必须保证写路径不可绕过,且校验与写入之间有一致性安排;先查租约再转发仍会留下竞争窗口。

取消也是一个持久状态转换。先记录取消,再停止安排新的业务动作;终态查询、对账和必要清理按允许范围继续。已发出请求可能成功,仍需记录结果并对账。若业务需要纠正已经产生的对象,应按明确权限执行后续动作,不能把本地状态倒回去当成外部事实消失。工程上分别测试陈旧执行、重复意图、取消后迟到结果,并用操作 ID、执行代次和外部对象串联证据;多个机制共同覆盖故障,而不是用一个“锁”包办所有语义。

常见追问:

  1. 有 fencing 还需要幂等吗? 需要。当前有效进程也可能因响应丢失重复提交同一动作;fencing 拦旧执行者,幂等识别重复业务意图,二者判断条件不同。
  2. 取消成功是否表示没有外部副作用? 只说明取消请求达到约定状态。还要区分未发出、执行中和结果已确认;对迟到成功结果保留记录并执行既定处理。
  3. 数据库里的最大令牌能保护另一个 SaaS 吗? 单独记录不能。要让真实写入路径参与检查或采用该服务可提供的条件写、幂等与查询机制,并描述剩余竞争窗口。

实战案例:

政策发布任务 A 暂停,B 接管后用令牌 42 更新报告状态;A 随后恢复,用 41 提交旧版本。测试存储拒绝旧令牌,避免覆盖 B。此时用户又取消任务,系统阻止后续发布调度,但此前已发出的工单请求返回成功,于是记录 T9 并进入对账。验收分别核对旧写被拒绝、取消后不再派发新的业务动作,终态查询、对账和必要清理按允许范围继续、迟到对象没有被伪装成不存在,三项证据不能由一个“任务已取消”字段代替。

常见误区:

认为租约过期会杀死旧进程;把令牌校验放在可绕过的入口;把停止等待当成撤销远端写入。

微练习:

画出 A 暂停、B 获得 42、A 苏醒、用户取消的时间线。验收:标出谁在何处拒绝 41,哪些请求已在途,如何识别重复意图,以及哪些结果仍需对账。

学习与参考: 配套学习章 · Fencing Token 原始讨论 · AWS 幂等 API

返回进阶题库目录