cloudflare-workflows

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Cloudflare Workflows

Cloudflare Workflows

Workflows provide durable multi-step execution for Workers. Steps persist state, survive restarts, support retries, and can sleep for days.

Workflows 为 Workers 提供持久化的多步骤执行能力。步骤会持久化状态,可在重启后继续运行,支持重试机制,并且可以休眠数天。

Quick Start

快速开始

Create Workflow

创建工作流

typescript
// src/index.ts
import { WorkflowEntrypoint, WorkflowStep, WorkflowEvent } from "cloudflare:workers";

interface Env {
  MY_WORKFLOW: Workflow;
}

interface Params {
  userId: string;
  action: string;
}

export class MyWorkflow extends WorkflowEntrypoint<Env, Params> {
  async run(event: WorkflowEvent<Params>, step: WorkflowStep) {
    const user = await step.do("fetch user", async () => {
      const resp = await fetch(`https://api.example.com/users/${event.payload.userId}`);
      return resp.json();
    });

    await step.sleep("wait before processing", "1 hour");

    const result = await step.do("process action", async () => {
      return { processed: true, user: user.id };
    });

    return result; // Available in instance.status().output
  }
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const instance = await env.MY_WORKFLOW.create({
      params: { userId: "123", action: "activate" },
    });
    return Response.json({ instanceId: instance.id });
  },
};
typescript
// src/index.ts
import { WorkflowEntrypoint, WorkflowStep, WorkflowEvent } from "cloudflare:workers";

interface Env {
  MY_WORKFLOW: Workflow;
}

interface Params {
  userId: string;
  action: string;
}

export class MyWorkflow extends WorkflowEntrypoint<Env, Params> {
  async run(event: WorkflowEvent<Params>, step: WorkflowStep) {
    const user = await step.do("fetch user", async () => {
      const resp = await fetch(`https://api.example.com/users/${event.payload.userId}`);
      return resp.json();
    });

    await step.sleep("wait before processing", "1 hour");

    const result = await step.do("process action", async () => {
      return { processed: true, user: user.id };
    });

    return result; // Available in instance.status().output
  }
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const instance = await env.MY_WORKFLOW.create({
      params: { userId: "123", action: "activate" },
    });
    return Response.json({ instanceId: instance.id });
  },
};

wrangler.jsonc

wrangler.jsonc

jsonc
{
  "name": "my-workflow-worker",
  "main": "src/index.ts",
  "workflows": [
    {
      "name": "my-workflow",
      "binding": "MY_WORKFLOW",
      "class_name": "MyWorkflow"
    }
  ]
}
jsonc
{
  "name": "my-workflow-worker",
  "main": "src/index.ts",
  "workflows": [
    {
      "name": "my-workflow",
      "binding": "MY_WORKFLOW",
      "class_name": "MyWorkflow"
    }
  ]
}

Deploy

部署

bash
npx wrangler deploy

bash
npx wrangler deploy

Core Concepts

核心概念

WorkflowEntrypoint

WorkflowEntrypoint

typescript
export class MyWorkflow extends WorkflowEntrypoint<Env, Params> {
  async run(event: WorkflowEvent<Params>, step: WorkflowStep) {
    // Workflow logic with steps
    return optionalResult;
  }
}
typescript
export class MyWorkflow extends WorkflowEntrypoint<Env, Params> {
  async run(event: WorkflowEvent<Params>, step: WorkflowStep) {
    // Workflow logic with steps
    return optionalResult;
  }
}

WorkflowEvent

WorkflowEvent

typescript
interface WorkflowEvent<T> {
  payload: Readonly<T>; // Immutable input params
  timestamp: Date; // Creation time
  instanceId: string; // Unique instance ID
}
Warning: Event payload is immutable. Changes are NOT persisted across steps. Return state from steps instead.
typescript
interface WorkflowEvent<T> {
  payload: Readonly<T>; // Immutable input params
  timestamp: Date; // Creation time
  instanceId: string; // Unique instance ID
}
警告:事件负载不可变。跨步骤的修改不会被持久化,请通过步骤返回值来传递状态。

WorkflowStep

WorkflowStep

typescript
interface WorkflowStep {
  do<T>(name: string, callback: () => Promise<T>): Promise<T>;
  do<T>(name: string, config: StepConfig, callback: () => Promise<T>): Promise<T>;
  sleep(name: string, duration: Duration): Promise<void>;
  sleepUntil(name: string, timestamp: Date | number): Promise<void>;
  waitForEvent<T>(name: string, options: WaitOptions): Promise<T>;
}
See api.md for full type definitions.

typescript
interface WorkflowStep {
  do<T>(name: string, callback: () => Promise<T>): Promise<T>;
  do<T>(name: string, config: StepConfig, callback: () => Promise<T>): Promise<T>;
  sleep(name: string, duration: Duration): Promise<void>;
  sleepUntil(name: string, timestamp: Date | number): Promise<void>;
  waitForEvent<T>(name: string, options: WaitOptions): Promise<T>;
}
完整类型定义请参考 api.md

Steps

步骤操作

Basic Step

基础步骤

typescript
const result = await step.do("step name", async () => {
  const response = await fetch("https://api.example.com/data");
  return response.json(); // State persisted
});
typescript
const result = await step.do("step name", async () => {
  const response = await fetch("https://api.example.com/data");
  return response.json(); // State persisted
});

Step with Config

带配置的步骤

typescript
const data = await step.do(
  "call external API",
  {
    retries: {
      limit: 10,
      delay: "30 seconds",
      backoff: "exponential",
    },
    timeout: "5 minutes",
  },
  async () => {
    return await externalApiCall();
  }
);
typescript
const data = await step.do(
  "call external API",
  {
    retries: {
      limit: 10,
      delay: "30 seconds",
      backoff: "exponential",
    },
    timeout: "5 minutes",
  },
  async () => {
    return await externalApiCall();
  }
);

Default Step Config

默认步骤配置

typescript
const defaultConfig = {
  retries: {
    limit: 5,
    delay: 10000, // 10 seconds
    backoff: "exponential",
  },
  timeout: "10 minutes",
};
OptionTypeDefaultDescription
retries.limit
number5Max attempts (use
Infinity
for unlimited)
retries.delay
string/number10000Delay between retries
retries.backoff
stringexponential
constant
,
linear
,
exponential
timeout
string/number10 minPer-attempt timeout

typescript
const defaultConfig = {
  retries: {
    limit: 5,
    delay: 10000, // 10 seconds
    backoff: "exponential",
  },
  timeout: "10 minutes",
};
选项类型默认值描述说明
retries.limit
number5最大重试次数(使用
Infinity
表示无限制)
retries.delay
string/number10000重试间隔时间
retries.backoff
stringexponential重试策略:
constant
(固定间隔)、
linear
(线性增长)、
exponential
(指数增长)
timeout
string/number10 min单次尝试的超时时间

Sleep & Scheduling

休眠与调度

Relative Sleep

相对时间休眠

typescript
await step.sleep("wait before retry", "1 hour");
await step.sleep("short pause", 5000); // 5 seconds (ms)
Duration units:
second
,
minute
,
hour
,
day
,
week
,
month
,
year
.
typescript
await step.sleep("wait before retry", "1 hour");
await step.sleep("short pause", 5000); // 5 seconds (ms)
时间单位
second
minute
hour
day
week
month
year

Sleep Until Date

指定时间点休眠

typescript
const targetDate = new Date("2024-12-31T00:00:00Z");
await step.sleepUntil("wait until new year", targetDate);

// Or with timestamp
await step.sleepUntil("wait until launch", Date.parse("24 Oct 2024 13:00:00 UTC"));
Maximum sleep: 365 days.
Note:
step.sleep
and
step.sleepUntil
do NOT count towards the 1024 steps limit.

typescript
const targetDate = new Date("2024-12-31T00:00:00Z");
await step.sleepUntil("wait until new year", targetDate);

// 或使用时间戳
await step.sleepUntil("wait until launch", Date.parse("24 Oct 2024 13:00:00 UTC"));
最大休眠时长:365天。
注意
step.sleep
step.sleepUntil
不计入1024步的限制。

Wait for Events

等待事件

Wait in Workflow

工作流内等待事件

typescript
const approval = await step.waitForEvent<{ approved: boolean }>("wait for approval", {
  type: "user_approval",
  timeout: "7 days",
});

if (approval.approved) {
  await step.do("proceed", async () => {
    /* ... */
  });
}
Default timeout: 24 hours.
Timeout behavior: Throws error and fails instance. Use try-catch to continue:
typescript
try {
  const event = await step.waitForEvent("optional event", { type: "update", timeout: "1 hour" });
} catch (e) {
  // Continue without event
}
typescript
const approval = await step.waitForEvent<{ approved: boolean }>("wait for approval", {
  type: "user_approval",
  timeout: "7 days",
});

if (approval.approved) {
  await step.do("proceed", async () => {
    /* ... */
  });
}
默认超时时间:24小时。
超时行为:触发错误并终止实例。可使用try-catch继续执行:
typescript
try {
  const event = await step.waitForEvent("optional event", { type: "update", timeout: "1 hour" });
} catch (e) {
  // 无事件时继续执行
}

Send Event from Worker

从Worker发送事件

typescript
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const { instanceId, approved } = await request.json();
    const instance = await env.MY_WORKFLOW.get(instanceId);

    await instance.sendEvent({
      type: "user_approval", // Must match waitForEvent type
      payload: { approved },
    });

    return new Response("Event sent");
  },
};
Event buffering: Events can be sent before Workflow reaches
waitForEvent
. They are buffered and delivered when the matching step executes.
See events.md for REST API.

typescript
export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    const { instanceId, approved } = await request.json();
    const instance = await env.MY_WORKFLOW.get(instanceId);

    await instance.sendEvent({
      type: "user_approval", // 必须与waitForEvent的type匹配
      payload: { approved },
    });

    return new Response("Event sent");
  },
};
事件缓冲:可以在工作流到达
waitForEvent
步骤之前发送事件,事件会被缓冲,直到匹配的步骤执行时再交付。
REST API详情请参考 events.md

Error Handling

错误处理

NonRetryableError

NonRetryableError

typescript
import { NonRetryableError } from "cloudflare:workflows";

await step.do("validate input", async () => {
  if (!event.payload.data) {
    throw new NonRetryableError("Missing required data");
  }
  return event.payload.data;
});
typescript
import { NonRetryableError } from "cloudflare:workflows";

await step.do("validate input", async () => {
  if (!event.payload.data) {
    throw new NonRetryableError("Missing required data");
  }
  return event.payload.data;
});

Catch and Continue

捕获异常并继续执行

typescript
try {
  await step.do("risky operation", async () => {
    await riskyApiCall();
  });
} catch (error) {
  await step.do("handle failure", async () => {
    await sendAlertEmail(error.message);
  });
}
typescript
try {
  await step.do("risky operation", async () => {
    await riskyApiCall();
  });
} catch (error) {
  await step.do("handle failure", async () => {
    await sendAlertEmail(error.message);
  });
}

Workflow States

工作流状态

StatusDescription
queued
Waiting to start
running
Actively executing
paused
Manually paused
waiting
Sleeping or waiting for event
waitingForPause
Pause requested, waiting to take effect
complete
Successfully finished
errored
Failed (uncaught exception or retry limit)
terminated
Manually terminated

状态描述说明
queued
等待启动
running
正在执行
paused
手动暂停
waiting
休眠或等待事件
waitingForPause
已请求暂停,等待生效
complete
执行成功完成
errored
执行失败(未捕获异常或达到重试上限)
terminated
手动终止

Workflow Bindings

工作流绑定

Create Instance

创建实例

typescript
const instance = await env.MY_WORKFLOW.create({
  id: "order-12345", // Optional custom ID (max 100 chars)
  params: { orderId: 12345 },
});
console.log(instance.id);
typescript
const instance = await env.MY_WORKFLOW.create({
  id: "order-12345", // 可选自定义ID(最多100字符)
  params: { orderId: 12345 },
});
console.log(instance.id);

Create Batch

批量创建实例

typescript
const instances = await env.MY_WORKFLOW.createBatch([{ params: { userId: "1" } }, { params: { userId: "2" } }, { params: { userId: "3" } }]);
// Up to 100 instances per batch
typescript
const instances = await env.MY_WORKFLOW.createBatch([{ params: { userId: "1" } }, { params: { userId: "2" } }, { params: { userId: "3" } }]);
// 每批最多创建100个实例

Get Instance

获取实例

typescript
const instance = await env.MY_WORKFLOW.get("order-12345");
typescript
const instance = await env.MY_WORKFLOW.get("order-12345");

Instance Methods

实例方法

typescript
await instance.pause(); // Pause execution
await instance.resume(); // Resume paused
await instance.terminate(); // Stop permanently
await instance.restart(); // Restart from beginning

const status = await instance.status();
console.log(status.status); // "running", "complete", etc.
console.log(status.output); // Return value from run()
console.log(status.error); // { name, message } if errored

await instance.sendEvent({
  type: "approval",
  payload: { approved: true },
});

typescript
await instance.pause(); // 暂停执行
await instance.resume(); // 恢复暂停的实例
await instance.terminate(); // 永久终止实例
await instance.restart(); // 从开头重启实例

const status = await instance.status();
console.log(status.status); // "running", "complete", 等
console.log(status.output); // run()方法的返回值
console.log(status.error); // 执行失败时的错误信息 { name, message }

await instance.sendEvent({
  type: "approval",
  payload: { approved: true },
});

Rules of Workflows

工作流使用规则

✅ DO

✅ 推荐做法

  • Make steps granular and self-contained
  • Return state from steps (only way to persist)
  • Name steps deterministically
  • await
    all step calls
  • Keep step return values under 1 MiB
  • Use idempotent operations in steps
  • Base conditions on
    event.payload
    or step returns
  • 步骤拆分粒度适中且独立
  • 通过步骤返回值传递状态(唯一持久化方式)
  • 步骤名称具有确定性
  • 所有步骤调用都使用
    await
  • 步骤返回值大小控制在1 MiB以内
  • 步骤内使用幂等操作
  • 基于
    event.payload
    或步骤返回值判断分支

❌ DON'T

❌ 禁止做法

  • Store state outside steps (lost on restart)
  • Mutate
    event.payload
    (changes not persisted)
  • Use non-deterministic step names (
    Date.now()
    ,
    Math.random()
    )
  • Skip
    await
    on step calls
  • Put entire logic in one step
  • Call multiple unrelated services in one step
  • Do heavy CPU work in single step
  • 在步骤外部存储状态(重启后会丢失)
  • 修改
    event.payload
    (修改不会被持久化)
  • 使用非确定性的步骤名称(如
    Date.now()
    Math.random()
  • 步骤调用不使用
    await
  • 将所有逻辑放在单个步骤中
  • 单个步骤内调用多个无关服务
  • 单个步骤内执行大量CPU密集型工作

Step State Persistence

步骤状态持久化示例

typescript
// ✅ Good: Return state from step
const userData = await step.do("fetch user", async () => {
  return await fetchUser(userId);
});

// ❌ Bad: State stored outside step (lost on restart)
let userData;
await step.do("fetch user", async () => {
  userData = await fetchUser(userId); // Will be lost!
});

typescript
// ✅ 正确:从步骤返回状态
const userData = await step.do("fetch user", async () => {
  return await fetchUser(userId);
});

// ❌ 错误:状态存储在步骤外部(重启后丢失)
let userData;
await step.do("fetch user", async () => {
  userData = await fetchUser(userId); // 会丢失!
});

Wrangler Commands

Wrangler 命令

bash
undefined
bash
undefined

List instances

列出实例

wrangler workflows instances list my-workflow
wrangler workflows instances list my-workflow

Describe instance

查看实例详情

wrangler workflows instances describe my-workflow --id <instance-id>
wrangler workflows instances describe my-workflow --id <instance-id>

Terminate instance

终止实例

wrangler workflows instances terminate my-workflow --id <instance-id>
wrangler workflows instances terminate my-workflow --id <instance-id>

Trigger new instance

触发新实例

wrangler workflows trigger my-workflow --params '{"key": "value"}'
wrangler workflows trigger my-workflow --params '{"key": "value"}'

Delete Workflow

删除工作流

wrangler workflows delete my-workflow

---
wrangler workflows delete my-workflow

---

Limits

限制条件

FeatureFreePaid
CPU time per step10 ms30 sec (max 5 min)
Wall clock per stepUnlimitedUnlimited
State per step1 MiB1 MiB
Event payload1 MiB1 MiB
Total state per instance100 MB1 GB
Max sleep duration365 days365 days
Max steps per Workflow10241024
Concurrent instances2510,000
Instance creation rate100/sec100/sec
Queued instances100,0001,000,000
Subrequests per instance50/req1000/req
Instance ID length100 chars100 chars
Retention (completed)3 days30 days
Note: Instances in
waiting
state (sleeping, waiting for event) do NOT count against concurrency limits.
功能项免费版付费版
单步骤CPU时间10 ms30秒(最大5分钟)
单步骤实际运行时间无限制无限制
单步骤状态大小1 MiB1 MiB
事件负载大小1 MiB1 MiB
单实例总状态大小100 MB1 GB
最大休眠时长365天365天
单工作流最大步骤数10241024
并发实例数2510,000
实例创建速率100/秒100/秒
排队实例数100,0001,000,000
单实例子请求数50/请求1000/req
实例ID长度100字符100 chars
已完成实例保留时长3天30天
注意:处于
waiting
状态的实例(休眠或等待事件)不计入并发限制。

Increase CPU Limit

提升CPU限制

jsonc
{
  "limits": {
    "cpu_ms": 300000 // 5 minutes
  }
}

jsonc
{
  "limits": {
    "cpu_ms": 300000 // 5分钟
  }
}

Pricing

定价

Based on Workers Standard pricing:
MetricFreePaid
Requests100K/day (shared)10M/mo included, +$0.30/M
CPU time10 ms/invocation30M ms/mo included, +$0.02/M ms
Storage1 GB1 GB included, +$0.20/GB-mo
Storage notes:
  • Calculated across all instances (running, sleeping, completed)
  • Deleting instances frees storage (updates within minutes)
  • Free plan: instance errors if storage limit reached
See pricing.md for details.

基于 Workers 标准版定价:
指标免费版付费版
请求量每日10万次(共享额度)每月1000万次免费额度,超出后$0.30/百万次
CPU时间每次调用10 ms每月3000万ms免费额度,超出后$0.02/百万ms
存储1 GB1 GB免费额度,超出后$0.20/GB-月
存储说明
  • 计算所有实例的总存储量(运行中、休眠中、已完成)
  • 删除实例会释放存储空间(数分钟内更新)
  • 免费版:实例存储超出限制时会执行失败
详情请参考 pricing.md

Prohibitions

禁止行为

  • ❌ Do not mutate
    event.payload
    (changes not persisted)
  • ❌ Do not store state outside steps
  • ❌ Do not use non-deterministic step names
  • ❌ Do not exceed 1 MiB per step return
  • ❌ Do not skip
    await
    on step calls
  • ❌ Do not rely on in-memory state between steps

  • ❌ 不要修改
    event.payload
    (修改不会被持久化)
  • ❌ 不要在步骤外部存储状态
  • ❌ 不要使用非确定性的步骤名称
  • ❌ 不要让单步骤返回值超过1 MiB
  • ❌ 不要省略步骤调用的
    await
  • ❌ 不要依赖步骤间的内存状态

References

参考文档

  • api.md — Full API reference
  • events.md — Event handling and REST API
  • patterns.md — Saga, approval, reminders
  • pricing.md — Billing details
  • api.md — 完整API参考
  • events.md — 事件处理与REST API
  • patterns.md — 分布式事务、审批流程、提醒机制等模式
  • pricing.md — 计费详情

Cross-References (Skills)

关联技能

  • cloudflare-workers
    — Worker development
  • cloudflare-queues
    — Message queue integration
  • cloudflare-r2
    — Large state storage
  • cloudflare-kv
    — Key-value references
  • cloudflare-workers
    — Worker开发
  • cloudflare-queues
    — 消息队列集成
  • cloudflare-r2
    — 大文件状态存储
  • cloudflare-kv
    — 键值对存储引用