一个前提的改变引出了一次系统重构Cloudflare Workflows 最初的设计出发点是服务于人触发的工作流用户注册、下单、提交表单……这类场景的特点是触发频率受人的操作速度约束并发压力相对可控。但随着 AI Agent 的普及情况发生了根本性变化。Agent 不需要人一步步点击它以机器的速度创建任务。一个 Agent 会话可以在几秒内发起数十个 Workflow 实例而当成百上千个 Agent 同时运行时实例的创建量可以在瞬间达到数千。与此同时Agent 本身也需要一个持久、可靠的执行引擎来承载它的工作——每一步可独立重试、支持暂停等待人工审批、在发生故障时不丢失进度。Workflows 正好满足这些需求。这种人触发到机器触发的量变最终迫使 Cloudflare 重新审视并彻底重构 Workflows 的控制平面。Workflows 的核心机制Workflows 是 Cloudflare 构建在自家开发者平台之上的持久执行引擎用于编排多步骤应用。一个典型的 Workflow 如下exportclassMyWorkflowextendsWorkflowEntrypoint{asyncrun(event,step){constdataawaitstep.do(fetch-data,async(){returnfetchFromAPI();});constapprovalawaitstep.waitForEvent(approval,{type:approval,timeout:24 hours,});awaitstep.do(process-and-save,async(){returnstore(transform(data));});}}每个step.do都是独立可重试的执行单元step.waitForEvent可以让流程挂起等待外部事件整个 Workflow 实例的状态持久化在 Durable ObjectsDO之上。V1 架构一个 DO 撑起整个账户在 V1 的控制平面中Cloudflare 为每个 Workflow 实例维护了一个EngineDO负责执行具体的步骤逻辑、重试策略和睡眠调度。这是 1:1 比例的实例和 Engine 一一对应。而在整个账户层面存在一个全局唯一的AccountDO它负责管理该账户下所有 Workflow 实例的元数据与生命周期。这个设计在流量较低时运行良好。但问题在于无论是创建实例、更新状态还是列举实例所有操作都必须经过这个单一的 Account DO。当用户的并发量提升成千上万个实例同时启动和结束时Account DO 每秒要承受的请求量迅速堆积成为整个系统的性能天花板。V1 的硬性限制由此而来最大并发实例数4,500每 10 秒最多创建实例数100 × 10 约 1,000这些不是人为设定的保守值而是架构本身决定的上限。V2 架构水平扩展打破单点瓶颈重新设计时Cloudflare 团队围绕一个核心原则展开一个实例存在的唯一可信来源应该是它自己的 Engine而不是任何中心节点。V2 引入了两个新的关键组件SousChef分担 Account 的压力Sous Chef在法语厨房术语中是副厨的意思负责协助主厨Account处理具体事务。在 V2 中Account 不再直接管理所有实例。取而代之的是每个 Workflow 都有若干个 SousChef DO每个 SousChef 负责该 Workflow 下一个子集的实例元数据和生命周期。这些 SousChef 再定期汇报给 Account将汇报频率和数据量都控制在可管理的范围内。一个额外的收益原本 Workflows 只有账户级别的隔离V2 无意间实现了工作流级别的隔离——同一账户内不同 Workflow 的 SousChef 互不干扰。Gatekeeper并发槽位的租约系统Gatekeeper 的职责是将并发槽位concurrency slots按需分配给各个 SousChef。其工作流程如下当一个新实例被创建它被随机分配给账户内的某个 SousChefSousChef 向 Account 发起请求申请一个并发槽位Account 决定授予槽位或将实例排入等待队列一旦槽位被授予SousChef 触发对应 Engine 的执行并承担起确保该实例不卡死的职责。Gatekeeper 的关键设计是周期性批量通信SousChef 与 Account 之间每秒通信一次每次将所有槽位请求批量合并为一次 JSRPC 调用。这从根本上保证了实例创建的高峰无法压垮 Account。此外这种周期性机制还带来了天然的公平性已经在运行中、只是被唤醒的实例会被优先分配槽位而不是被新创建的实例挤掉。新的实例创建路径在 V2 下创建一个实例的请求路径变为检查当前控制平面版本查找本地缓存中是否有该 Workflow 的版本信息如无去 Account 查询并缓存将必要的元数据实例 payload、创建时间直接写入 Engine 自身。Engine 存在的确认信号在后台异步完成。为防止后台任务因 DO 驱逐或服务器故障而失败系统在热路径上同时设置了一个DO Alarm——即便后台任务失败Alarm 也会确保实例最终被正确启动。Durable Object Alarm 提供至少执行一次的保证并内置自动重试。Cloudflare 在整个 V2 架构中大量使用后台任务 Alarm 兜底的组合将非关键操作从热路径中剥离同时不牺牲可靠性。零停机迁移开着车换轮子新架构设计好之后Cloudflare 面临的下一个挑战是如何把数百万个已有实例、数千名已有客户在不停机、不中断的情况下迁移到新的控制平面团队的核心决策是将原有的 AccountOld DO 原地改造成 SousChef而不是迁移数据。由于 V1 的 AccountOld 和 V2 的 SousChef 在 SQL 表结构上完全一致团队只需在 AccountOld 的构造函数中注入 SousChef 实例并根据当前版本标志决定走哪条代码路径import{SousChef}fromrepo/souschef;classAccountOldextendsDurableObject{constructor(state,env){if(this.currentVersionControlPlaneVersions.SOUS_CHEFS){this.sousChefnewSousChef(this.ctx,this.env);awaitthis.sousChef.setup();}}asyncupdateInstance(params){if(this.currentVersionControlPlaneVersions.SOUS_CHEFS){returnthis.sousChef.updateInstance(params);}// 旧逻辑保持不变}}当账户被启用 V2 时三件事几乎同时发生所有新实例的创建请求路由到新的 SousChefAccountOld 不再接收新实例AccountOld 开始以 SousChef 模式运行新的 Account DO 携带对应元数据被启动。随着旧实例的保留期陆续到期AccountOld 逐渐退出历史舞台最终被彻底关闭。整个迁移过程用 Cloudflare 工程师的话来说是开着车换轮子——没有任何停机没有任何用户感知到切换的发生。新的能力上限完成重构后Workflows 的限制大幅提升指标V1 上限V2 上限最大并发实例数4,50050,000实例创建速率账户级100/10s300/s最大排队实例数每个 Workflow1,000,0002,000,000这些数字背后更重要的变化是V2 的限制是弹性的Cloudflare 可以根据需要继续调整而不像 V1 那样受限于架构本身的硬上限。如果有更高的需求可以联系账户团队单独申请。几点工程上的启示这次重构有几个值得关注的工程思路1. 单点聚合是分布式系统的天然敌人。V1 的 Account DO 承担了太多职责V2 的核心就是把这些职责拆散、下移让每个组件只做它最该做的事。2. 异步 兜底是高吞吐与高可靠并存的关键。把非关键操作从热路径剥离出去用后台任务处理再用 Alarm 兜底这种模式让主流程保持快速响应同时不依赖一切都会成功的乐观假设。3. 数据结构的前瞻性设计让零停机迁移成为可能。正因为 V1 和 V2 的 SQL 表结构相同团队才得以在不搬迁数据的前提下完成迁移。否则面对数百万实例的数据搬运迁移的复杂度和风险会指数级上升。4. 架构演进要为可继续提升留余地。V2 不是一个终态而是一个可以继续调整上限、持续扩展的弹性基座。这种设计哲学比给出一个更大的固定数字更有价值。随着 AI Agent 逐渐从实验性功能演变为持续运行的生产基础设施对底层执行引擎的要求也将持续演化。Cloudflare 这次对 Workflows 控制平面的重构是对这一趋势的一次技术层面的正式回应。原文链接https://blog.cloudflare.com/workflows-v2/