跳转到主要内容
文档运行自动续跑

意外中断与自动续跑

工作流跑到一半被打断怎么办?配好 recovery 与 idempotent,跑断点续传、避免重复副作用。

"一次没跑完怎么办"是生产级工作流必须回答的问题。Braidrun 提供两种处理方案:

  • 默认:安全中断 — 把 execution 标为 INTERRUPTED,等你看清楚再手动从中间某一步"重试"。
  • 可选:自动续跑 — 你显式声明"这条工作流可以续跑 + 哪些步骤幂等"后,平台自动从中断点继续。
中断到底指什么

两类:

  • 平台侧 —— 服务重启、实例被替换、宿主机故障。这些我们努力避免但不能 100%。
  • 你侧 —— 你主动"取消"某次 execution(停在 CANCELLED,不是 INTERRUPTED)。

只有前一类才会进入"自动续跑"流程,CANCELLED 的 execution 不会自动跑。

默认行为:安全中断

发生平台侧中断时,平台:

  1. 把该 execution 状态标为 INTERRUPTED;
  2. 保留所有已完成 step 的结果、产物、日志;
  3. 你收到一条站内通知(也会按你的通知配置邮件 / Slack);
  4. 你去执行详情页,可以"从失败那一步重试"—— 平台复用前面 step 的结果。

这种默认对所有工作流都可用,不需要配置。适合:

  • 工作流含对外副作用(发邮件 / 扣款 / 改数据库)
  • 生产还不确定"重启续跑是否安全"时

可选:自动续跑

如果你的工作流是纯数据管道(只读 API + 生成报表),可以开启自动续跑 —— 中断发生后平台自动从中断点继续跑,不需要你手动点。

启用的两层 opt-in

要让自动续跑生效,你需要在 YAML 里两层都声明:

  1. workflow 级: 声明 recovery.autoResumeOnRestart: true
  2. step 级: 安全重跑的步骤标 idempotent: true

完整示例

yaml
name: daily-asa-digest
version: "1.0.0"

recovery:
  autoResumeOnRestart: true
  policy: RESUME_FROM_LAST_INCOMPLETE
  maxAutoResumeAttempts: 3

steps:
  - id: fetch_asa_data
    type: sub_workflow
    module: dingyue-module-asa-fetch
    idempotent: true           # 只读拉取,可重跑

  - id: build_excel
    type: sub_workflow
    module: dingyue-module-excel-report
    idempotent: true           # 生成文件到产物目录,可重跑

  - id: notify_team
    type: sub_workflow
    module: dingyue-module-slack-deliver
    # 不写 idempotent —— 默认 false,发消息不可重跑

三种 recovery.policy

policy含义适合场景
ABORT不自动恢复,等于回到默认行为测试阶段
RESUME_FROM_LAST_INCOMPLETE默认。从第一个非 COMPLETED 的 step 开始重跑。数据管道、只读 API 聚合、纯计算
RESUME_FROM_START整条 workflow 从头开始重跑数据源可能在中断期间变化、需要刷新的场景

idempotent 怎么标

判断一个 step 是否 idempotent 的黄金标准:

"同样的输入跑两次,会不会产生副作用?"

如果会(对外发消息、扣款、写订单),就不要加 idempotent。

Step 性质idempotent
只读 API 查询(拉报表、列 App)✓ true
纯计算 / 数据转换✓ true
生成 Markdown / Excel 到产物目录✓ true(重跑前旧产物会被清理)
LLM 推理(无副作用工具)✓ true(会重新计 tokens,但语义安全)
发邮件 / Telegram / Slack / 飞书✗ false
写入外部 DB / 改广告出价 / 下单 / 扣款✗ false
Webhook 出站调用✗ false(除非对方 endpoint 明确去重)
manual_approval✗ false(续跑会再 ping 一次审批人,体验差)
默认值是 false —— 安全为先

不写 idempotent 默认是 false。RESUME_FROM_LAST_INCOMPLETE 遇到非幂等 step 会降级为 ABORT —— 不自动跑,留给你手动。

自动续跑不会发生的几种情况

即使你配好了 recovery,以下几种 execution 仍然不会自动续跑:

  • 触发源是 Webhook —— Webhook payload 可能 at-most-once,平台不知道上游是否会 retry。
  • 触发源是 Scheduler —— scheduler 会按 cron 下一轮自行 re-fire。
  • 当前停在 manual_approval —— 等审批意味着本来就是阻塞状态。
  • workflow 定义文件在中断期间被修改 —— 平台检测到 hash mismatch,不确定新版是否兼容。

手动"从某一步重试"(随时可用)

不管工作流有没有配 recovery,执行详情页始终提供"从失败步骤重试"按钮:

  1. 打开一条 INTERRUPTED / FAILED 的 execution;
  2. 点失败 / 中断的 step 旁的「从这一步重试」;
  3. 前面已 COMPLETED 的 step 结果会被复用;这一步开始往下重新跑。

即使这一步不是 idempotent,你也可以手动重试 —— 因为这时是你作为人有意识地决定"值得重跑"。

续跑限额

防止系统把同一条 execution 来回重启"死循环":每条 execution 最多自动续跑 3 次。超过仍然失败就停下来等你处理。你可以在 recovery.maxAutoResumeAttempts 里覆盖(1-20)。

审计

每次自动续跑都会记审计事件:

  • execution.auto_resume — 成功续跑
  • execution.auto_resume.skipped — 按规则不应该续跑,带 reason

Admin 可以在审计日志里按这两个 event_type 过滤查看。

实战建议

  • 纯数据管道(ASA 日报、RSS 摘要):recovery + idempotent 全开,安心让它自动续跑。
  • 含外部副作用的(扣款、发消息、下单):不要开 auto resume。中断了人工决策。
  • 关键副作用步骤前加 manual_approval —— 审批本身是中断续跑的"天然阻塞点"。

下一步