六维教程

工作流编排基础

有些任务不是一次请求就能跑完的。处理一笔订单要查库存、扣款、发邮件、更新库,中间任何一步都可能失败,失败后还要能从断点续跑而不是从头再来。Cloudflare Workflows 就是用来编排这类多步骤任务的,它运行在 Workers(Cloudflare 的边缘计算函数服务)之上,把每一步的结果自动存下来,故障重启后接着往下走。这篇讲清楚工作流编排的核心概念,以及如何定义一个 Step 并把它绑定到 Worker 上跑起来。

什么是工作流编排

工作流编排解决的是多步骤任务的可靠执行问题。普通 Worker 处理一个请求,函数跑完就结束,中间状态全部丢失。工作流不一样,它把任务拆成若干 Step,每个 Step 执行完的结果会被持久化,整个流程可以跑几分钟、几小时甚至几天。

两种执行模型对比

对比项 普通 Worker 请求 Workflows 工作流
执行时长 单次请求,通常秒级 可长达数小时或数天
状态保留 不保留,请求结束即丢失 每个 Step 结果自动持久化
失败恢复 整个请求重跑 从最后成功的 Step 续跑
适用场景 即时响应、简单计算 多步骤、长耗时、需协调的任务
触发方式 收到 HTTP 请求即执行 通过绑定创建实例触发

这套机制在业界叫做持久执行(Durable Execution)。核心思想是程序把自己的执行进度隐式存下来,不用你手动往外部数据库写状态。Workflows 引擎负责存取,你只管写业务逻辑。

什么时候该用工作流

场景 普通 Worker 的问题 工作流的好处
电商订单处理 扣款后崩溃,库存与支付不一致 每步存档,崩溃后从断点续跑
文件上传后处理 转码耗时过长,请求早超时 异步编排,可长时间运行
用户注册流程 发邮件失败就要整个重来 单独重试失败步骤
数据同步与批处理 中途中断无法续传 进度持久化,断点续跑
定时周期任务 需要自己管调度和状态 内置调度,状态自动保留

Step 是什么

Step 是工作流的最小执行单元。一个工作流由若干 Step 顺序排列组成,每个 Step 做一件事,做完把结果交还给引擎保存。Step 提供四个方法,覆盖了执行、等待、休眠三类操作。

Step 方法一览

方法 作用 是否持久化
step.do 执行一段代码并存下返回值
step.sleep 休眠一段相对时长后继续
step.sleepUntil 休眠到某个固定时刻再继续
step.waitForEvent 暂停等待外部事件到达

最常用的是 step.do。它接收一个名字和一个回调函数,回调的返回值会被引擎存下来。下一次工作流重启走到这个 Step,直接读存档跳过执行,不会重复跑。

判断是否该拆成独立 Step 的原则很简单,问自己一句话,这段代码失败后要不要整段重跑。如果只想重跑出问题的部分,就把它单独拆成一个 Step。

编写第一个工作流

工作流是一个继承 WorkflowEntrypoint 的类,核心是 run 方法。先看一个最简单的例子,抓取数据然后处理。

import { WorkflowEntrypoint, WorkflowStep } from "cloudflare:workers";
import type { WorkflowEvent } from "cloudflare:workers";

type Params = { name?: string };

export class MyWorkflow extends WorkflowEntrypoint<Env, Params> {
  async run(event: WorkflowEvent<Params>, step: WorkflowStep) {
    // 第一步,抓取数据,结果自动持久化
    const data = await step.do("fetch data", async () => {
      const response = await fetch("https://api.cloudflare.com/client/v4/ips");
      return await response.json();
    });

    // 第二步,处理数据,用上一步的结果
    const result = await step.do("process data", async () => {
      return {
        name: event.payload.name ?? "World",
        ipCount: data.result.ipv4_cidrs.length,
      };
    });

    return result;
  }
}

几个关键点

要素 说明
WorkflowEntrypoint 必须继承的基类,泛型是 Env 和 Params
run 方法 工作流入口,接收 event 和 step 两个参数
event.payload 触发时传入的参数,整个流程里不可变
step.do 的名字 作为存档的键,必须确定性,不能含 Date.now 等随机值
回调返回值 必须可序列化,单个 Step 结果上限 1 MiB
run 的返回值 可选,会作为实例输出,可通过 status 查询

event 在整个工作流执行期间是不可变的。想在步骤之间传递数据,靠的是 step.do 的返回值,不要试图修改 event.payload。

Step 的名字是存档依据,名字一样就认为是同一个 Step。所以名字里不能塞随机数、时间戳这类不确定的值,否则每次重跑引擎都当成新 Step,存档就失效了。

绑定配置

工作流类写好后,要在 wrangler(Cloudflare 的命令行工具)配置文件里声明它,Worker 才能通过绑定访问。配置写在 wrangler.toml 里。

name = "my-workflow"
main = "src/index.ts"
compatibility_date = "2026-08-14"

[observability]
enabled = true

[[workflows]]
name = "my-workflow"
binding = "MY_WORKFLOW"
class_name = "MyWorkflow"

字段含义

字段 作用
name 工作流名称,部署后全局标识
binding 代码里访问的变量名,对应 env.MY_WORKFLOW
class_name 必须和导出的类名一致

class_name 对不上会报错,binding 写什么就在代码里用什么。一个 Worker 可以声明多个工作流,每个 [[workflows]] 块对应一个。

工作流内部还能访问其他绑定,比如 D1(Cloudflare 的无服务器 SQLite 数据库)、KV(Cloudflare 的键值存储)、R2(Cloudflare 的对象存储服务),通过 this.env 拿到,和普通 Worker 一样。

export class MyWorkflow extends WorkflowEntrypoint<Env, Params> {
  async run(event: WorkflowEvent<Params>, step: WorkflowStep) {
    const order = await step.do("load order", async () => {
      // 通过 this.env 访问 D1 绑定
      const row = await this.env.DB
        .prepare("SELECT * FROM orders WHERE id = ?")
        .bind(event.payload.orderId)
        .first();
      return row;
    });
    return order;
  }
}

触发与查询实例

工作流配置好之后,需要通过绑定创建实例来触发执行。通常是在 fetch 处理函数里调用 create。

export { MyWorkflow } from "./workflow";

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const url = new URL(request.url);
    const instanceId = url.searchParams.get("instanceId");

    // 传了 instanceId 就查询状态
    if (instanceId) {
      const instance = await env.MY_WORKFLOW.get(instanceId);
      return Response.json(await instance.status());
    }

    // 否则创建新实例,可传入参数
    const body = await request.json() as { name?: string };
    const instance = await env.MY_WORKFLOW.create({
      params: { name: body.name },
    });
    return Response.json({ instanceId: instance.id });
  },
} satisfies ExportedHandler<Env>;

实例操作方法

方法 作用
create 创建并启动一个新实例
get 按 ID 取回实例引用
instance.id 实例唯一标识
instance.status 查询执行状态和各步结果

create 接收可选参数对象,params 会作为 event.payload 传进 run。不传 params 也能跑,payload 就是空。create 返回的实例对象上有 id,拿这个 id 后续查询进度。

本地开发调试

wrangler dev 启动本地环境,工作流会在本地模拟执行。

npx wrangler dev

启动后用 curl 触发实例

curl http://localhost:8787 -H "Content-Type: application/json" -d '{"name":"测试"}'

返回的 instanceId 用来查状态

curl "http://localhost:8787?instanceId=实例ID"

命令行还能直接查实例详情,看每一步的执行情况

npx wrangler workflows instances list my-workflow
npx wrangler workflows instances describe my-workflow 实例ID

instances describe 的输出会列出每个 Step 的状态、返回值、重试次数、报错信息,调试时非常有用。

小结

工作流编排把多步骤任务拆成可独立重试的 Step,每个 Step 的结果自动持久化,故障后从断点续跑。基础套路就三步,写一个继承 WorkflowEntrypoint 的类用 step.do 定义步骤,在 wrangler.toml 里用 [[workflows]] 声明绑定,在 fetch 处理函数里调用 create 触发实例。下一篇讲状态如何持久化以及出错后怎么重试和超时控制。

下一篇 状态与错误处理

上一篇
Cloudflare Workers WebSocket
下一篇
状态与错误处理