Cloudflare Workflows 配置完全指南:wrangler.jsonc 绑定、步骤编排与跨脚本调用实战
【免费下载链接】skillsSkills Catalog for Codex项目地址: https://gitcode.com/GitHub_Trending/skills4/skills
本篇技术指南以仓库内 Workflows 配置参考 为核心骨架,系统讲解在 Cloudflare Workers 平台(cloudflare-deploy 技能体系中的 workflows 模块)上配置与编排多步骤长任务的全部要点:从wrangler.jsonc中 Workflow 的声明与限流设置,到step.do()的重试/超时/并行/条件/循环编排,再到跨脚本绑定与 Pages Functions 触发。读完本文,你将能独立搭建一个具备自动重试、状态持久化、可等待人工审批的生产级 Workflow,并掌握从配置到实例管理的完整闭环。
一、Workflows 是什么:先理解配置的落点
Cloudflare Workflows 是面向"多步骤、长运行、可持久化"业务逻辑的编排原语:每一步(Step)都是可独立重试的执行单元,步骤间状态自动持久化,失败不会丢失已完成的进度。它位于 SKILL.md 决策树中"Long-running multi-step jobs → workflows/"的分支,适用于邮件通知、数据管道、人工审批等场景。
Workflows 的核心配置载体是wrangler.jsonc——你在其中声明 Workflow 的名称、环境绑定(binding)、对应的 TypeScript 类名,以及全局资源上限;而步骤的编排逻辑写在类的方法里。因此,"配置"实际上分两个层面:文件级配置(wrangler.jsonc)与代码级配置(step.do()的选项对象)。下文依次展开。
二、wrangler.jsonc 基础配置:声明一个 Workflow
在wrangler.jsonc中注册 Workflow 的最小配置如下(完整示例来自 configuration.md):
{ "name": "my-worker", "main": "src/index.ts", "compatibility_date": "2025-01-01", // Use current date for new projects "observability": { "enabled": true // Enables Workflows dashboard + structured logs }, "workflows": [ { "name": "my-workflow", // Workflow name "binding": "MY_WORKFLOW", // Env binding "class_name": "MyWorkflow" // TS class name // "script_name": "other-worker" // For cross-script calls } ], "limits": { "cpu_ms": 300000 // 5 min max (default 30s) } }各字段的作用与取值要点:
| 字段 | 说明 |
|---|---|
name | Worker 名称,部署后在 Cloudflare 侧显示 |
main | 入口文件,通常是src/index.ts |
compatibility_date | 兼容性日期,新项目建议取当前日期,保证使用最新的 Workers 运行时 API |
observability.enabled | 打开 Workflows 仪表盘与结构化日志,生产排查必备 |
workflows[] | Workflow 声明数组,每项含name、binding、class_name;script_name用于跨脚本调用(见第六节) |
limits.cpu_ms | 单个步骤的 CPU 时间上限(毫秒)。默认 30s(30000ms),最大可提升到 5 分钟(300000ms) |
需要特别说明cpu_ms的语义:它计量的是活跃计算时间而非墙钟时间(wall-clock)。网络请求、数据库查询、step.sleep()等 I/O 等待都不计入 CPU 时间——这正是 gotchas.md 中"步骤提示 CPU 超限但实际运行不足 30s"这一困惑的根源:30s 限制指的是 30s 的纯计算量。
三、步骤配置:step.do() 的重试与超时
Workflow 的"配置重心"其实在step.do()。它有三个重载形式:
// 基本步骤:返回结果会被持久化,步骤名即缓存键 const data = await step.do('step name', async () => ({ result: 'value' })); // 带重试与超时配置的步骤 await step.do('api call', { retries: { limit: 10, // Default: 5, or Infinity delay: '10 seconds', // Default: 10000ms backoff: 'exponential' // constant | linear | exponential }, timeout: '30 minutes' // Per-attempt timeout (default: 10min) }, async () => { const res = await fetch('https://api.example.com/data'); if (!res.ok) throw new Error('Failed'); return res.json(); });配置项解析:
retries.limit:最大重试次数,默认 5,可设为Infinity表示无限重试;retries.delay:两次尝试之间的基础间隔,默认10000ms,接受'10 seconds'这类人类可读字符串,也接受毫秒数字;retries.backoff:退避策略,constant(恒定间隔)|linear(线性增长)|exponential(指数退避,生产环境对不稳定第三方 API 的首选);timeout:单次尝试(per-attempt)的超时,默认 10 分钟。注意它与limits.cpu_ms是两回事——前者是墙钟超时,后者是 CPU 计量。
与重试机制配套的错误语义:抛出普通Error视为可重试失败;抛出NonRetryableError(从cloudflare:workers导入)则放弃重试。这在 api.md 中有明确示例——例如 401 凭证失效时抛NonRetryableError('Invalid credentials')不要重试,网络失败抛普通Error等待自动重试。
3.1 并行步骤(Parallel Steps)
多个相互独立的步骤可以用Promise.all并发执行,互不阻塞:
const [user, settings] = await Promise.all([ step.do('fetch user', async () => this.env.KV.get(`user:${id}`)), step.do('fetch settings', async () => this.env.KV.get(`settings:${id}`)) ]);这是 Workflows 并发模型的核心优势之一:并行步骤仍然各自独立持久化、独立重试,失败互不影响。
3.2 条件步骤(Conditional Steps)
Workflows 的回放(replay)机制要求控制流必须是确定性的——即每次重放执行时分支判断必须产生相同结果。因此条件判断必须基于步骤输出或event.payload,而非Date.now()这类运行期随机值:
const config = await step.do('fetch config', async () => this.env.KV.get('flags', { type: 'json' }) ); // ✅ Deterministic (based on step output) if (config.enableEmail) { await step.do('send email', async () => sendEmail()); } // ❌ Non-deterministic (Date.now outside step) if (Date.now() > deadline) { /* BAD */ }正确做法是把非确定性判断搬进步骤内部:const isLate = await step.do('check', async () => Date.now() > deadline)(详见 gotchas.md 的 "Non-Deterministic Conditionals" 条目)。
3.3 动态步骤(Loops)
动态数量的步骤可以用循环生成,但要保证步骤名确定(通常取自数据本身的键):
const files = await step.do('list files', async () => this.env.BUCKET.list() ); for (const file of files.objects) { await step.do(`process ${file.key}`, async () => { const obj = await this.env.BUCKET.get(file.key); return processData(await obj.arrayBuffer()); }); }注意:若步骤名中混入Date.now()等非确定值,会导致重放时无法命中缓存、产生重复执行——这是 gotchas.md 中 "Non-Deterministic Step Names" 的典型陷阱,解决办法是改用event.instanceId等确定值。
四、多 Workflow 注册:一个 Worker 承载多个编排
单个 Worker 可以同时注册多个 Workflow,各自拥有独立的name、binding与class_name:
{ "workflows": [ {"name": "user-onboarding", "binding": "USER_ONBOARDING", "class_name": "UserOnboarding"}, {"name": "data-processing", "binding": "DATA_PROCESSING", "class_name": "DataProcessing"} ] }每个类均继承WorkflowEntrypoint,并携带自己独立的Params泛型类型(见 README.md 的 Quick Start:export class MyWorkflow extends WorkflowEntrypoint<Env, Params>)。部署前记得执行npx wrangler deploy;从 bindings/configuration.md 可以看到对应的创建命令npx wrangler workflows create my-workflow。
五、跨脚本绑定:Worker A 定义,Worker B 调用
当一个 Worker 需要触发另一个 Worker 中定义的 Workflow 时,通过script_name建立跨脚本引用。定义方(Worker A)正常声明 Workflow;调用方(Worker B)在workflows数组中用script_name指向定义方:
// Worker B (caller) { "workflows": [{ "name": "billing-workflow", "binding": "BILLING", "script_name": "billing-worker" // Points to Worker A }] }此后 Worker B 中env.BILLING即为指向 Worker A 内billing-workflow的句柄,可直接调用create()等方法。这与 Durable Objects 的跨脚本绑定("script_name": "my-worker")以及通用 service bindings(bindings/configuration.md 中的services[]配置)是同一套"跨 Worker 引用"思想在 Workflow 场景的落地。
六、Bindings:在步骤中访问全部平台能力
Workflow 步骤通过this.env访问所有 Cloudflare 绑定(KV、D1、R2、Workers AI、Vectorize 以及 Workflow 自身)。推荐的做法是先声明完整的Env类型:
type Env = { MY_WORKFLOW: Workflow; KV: KVNamespace; DB: D1Database; BUCKET: R2Bucket; AI: Ai; VECTORIZE: VectorizeIndex; }; await step.do('use bindings', async () => { const kv = await this.env.KV.get('key'); const db = await this.env.DB.prepare('SELECT * FROM users').first(); const file = await this.env.BUCKET.get('file.txt'); const ai = await this.env.AI.run('@cf/meta/llama-2-7b-chat-int8', { prompt: 'Hi' }); });这些绑定本身在wrangler.jsonc中声明(kv_namespaces、d1_databases、r2_buckets、ai、vectorize等字段,完整清单见 bindings/configuration.md)。修改配置后运行npx wrangler types可自动刷新类型定义;所有绑定合计上限为 64 个。
一个值得注意的边界:步骤返回的状态有 1 MiB 上限(实例总状态 100 MB / 1 GB 视套餐而定)。因此 patterns.md 与 gotchas.md 都强调:大数据写入 R2,步骤只返回对象键引用({ key: 'r2-object-key' })。
七、Pages Functions 触发 Workflow
Cloudflare Pages 的 Functions(functions/目录)可以通过 service bindings 触发 Workflow 实例。在 configuration.md 中的示例是functions/_middleware.ts:
// functions/_middleware.ts export const onRequest: PagesFunction<Env> = async ({ env, request }) => { const instance = await env.MY_WORKFLOW.create({ params: { url: request.url } }); return new Response(`Started ${instance.id}`); };对应的绑定在wrangler.jsonc的service_bindings下配置(将其与第六节的services[]写法对应:service binding 声明binding与目标service名称)。这样,任何 Pages 请求都能异步拉起一个持久化 Workflow,并立即返回实例 ID。
八、实例生命周期与配套 API(配置之外的关键操作)
配置完成后,运行期主要通过env.<BINDING>的实例 API 进行管理,这些 API 在 api.md 中有完整说明,此处摘要:
// 创建实例(id 可省略,自动生成;可自定义保留期) const instance = await env.MY_WORKFLOW.create({ id: crypto.randomUUID(), params: { userId: 'user123' }, retention: '30 days' // 覆盖默认保留期(Free 3 天 / Paid 30 天) }); // 批量创建(最多 100 个,幂等:已存在 ID 自动跳过) await env.MY_WORKFLOW.createBatch([{id: 'user1', params: {name: 'John'}}, ...]); // 查询与控制 const status = await instance.status(); // queued | running | paused | errored | terminated | complete | waiting | ... await instance.pause(); await instance.resume(); await instance.terminate(); await instance.restart(); // 向 waitForEvent 发送事件 await instance.sendEvent({type: 'approval', payload: { approved: true }});除 Worker 内触发外,还有三种常见触发源(api.md):
- Queue 消费触发:
queue(batch, env)handler 内逐条create(); - Cron 定时触发:
scheduled(event, env)内按调度时间创建实例; - Workflow 嵌套触发:父 Workflow 步骤内
create()子 Workflow(非阻塞)。
对应的 CLI 与 REST 操作:
# CLI:列出 / 触发 / 查询实例 npx wrangler workflows list npx wrangler workflows trigger my-workflow '{"userId":"user123"}' npx wrangler workflows instances list my-workflow npx wrangler workflows instances describe my-workflow instance-id npx wrangler workflows instances pause/resume/terminate my-workflow instance-id# REST:创建实例 curl -X POST "https://api.cloudflare.com/client/v4/accounts/{account_id}/workflows/{workflow_name}/instances" \ -H "Authorization: Bearer {token}" \ -d '{"id":"custom-id","params":{"userId":"user123"}}'九、限额速查:配置前必须了解的硬边界
gotchas.md 给出了完整限额表,影响配置决策的关键几项:
| 限制项 | Free | Paid | 说明 |
|---|---|---|---|
| 单步骤 CPU | 10ms | 30s(默认)/ 5min(最大) | 通过limits.cpu_ms配置 |
| 步骤返回状态 | 1 MiB | 1 MiB | 每步返回值上限 |
| 实例总状态 | 100 MB | 1 GB | 整个实例的状态 |
| 每 Workflow 步骤数 | 1,024 | 1,024 | step.sleep()不计入 |
| 并发实例 | 25 | 10k | waiting状态不计入 |
| 单步骤子请求 | 50 | 1,000 | 每步出站请求上限 |
| 状态保留期 | 3 天 | 30 天 | 完成后实例自动删除 |
| step timeout 默认 | 10 min | 10 min | 单次尝试 |
| waitForEvent 默认/最大 | 24h / 365 天 | 24h / 365 天 | 等待外部事件 |
关键推论:处于waiting状态(step.sleep()/step.waitForEvent())的实例不占用并发配额,因此可以支撑数百万个"沉睡中"的调度型 Workflow;但已完成/报错的实例会在保留期后被自动清理,重要数据必须在结束前导出到 KV/R2/D1(gotchas.md 的 "Instance Data Disappeared After Completion" 条目)。
十、从配置到可靠编排:最佳实践小结
综合 configuration.md 与 patterns.md 的 Best Practices,生产级配置应遵循:
- 步骤粒度细:一个 API 调用一个
step.do(),除非能证明幂等,否则不要写巨型步骤; - 幂等优先:先查后写(check-then-execute),例如扣费前先查询订阅是否已扣费,防止重试造成重复动作;
- 状态走步骤返回值:不要用模块级变量存状态,休眠(hibernation)后会丢失;
step.do()的返回值自动持久化; - 步骤名确定:用静态名或步骤输出派生名,禁止
Date.now(); - 条件判断确定:基于
event.payload或步骤输出,非确定性逻辑必须移入步骤; - 始终
await step.do():漏掉 await 会变成 fire-and-forget,破坏重试语义; - 大对象外置:超过 1 MiB 的数据存 R2,步骤只返回引用;
- 实例 ID 唯一:复用 ID 会冲突,可用
`${userId}-${Date.now()}`生成(放在步骤内以保证确定性场景安全); - waitForEvent 必须 try-catch:超时(默认 24h,最大 365 天)会抛异常,需捕获后走默认分支。
测试侧可使用@cloudflare/vitest-pool-workers+cloudflare:test的introspectWorkflowInstance内省 API,等待指定步骤完成或 mock 步骤返回值(详见 patterns.md 的 Testing Workflows 一节)。
延伸阅读
- Workflows 模块总览:核心概念、Quick Start 与阅读顺序
- Workflows API 参考:Step API、实例管理、触发方式、错误处理
- Workflows 常见陷阱:时间超限、状态丢失、幂等违反等排查
- Workflows 编排模式:图像管道、用户生命周期、人工审批、Fan-Out 等完整示例
- Bindings 配置参考:KV/D1/R2/AI/Service 等绑定的声明方式
【免费下载链接】skillsSkills Catalog for Codex项目地址: https://gitcode.com/GitHub_Trending/skills4/skills
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考