Workflow SDK:免Temporal部署,改代码不炸,告别Airflow画图!


vercel/workflow 是 Vercel 推出的一个开源 TypeScript SDK,官方名称为 Workflow SDK(也常被称为 Workflow DevKit)。它的核心目标是让开发者能轻松地为异步 JavaScript 代码添加持久性、可靠性和可观测性,从而构建能够暂停、恢复并轻松维护状态的应用和 AI 代理。

简单来说,它旨在解决编写长时间运行、有状态的后端逻辑时,传统方案(如消息队列、Kubernetes 或 Temporal)过于复杂的问题。Workflow SDK 让开发者能用普通的编程语言编写代码,并将编排能力融入应用本身,而非一个独立的服务。


最好的工作流引擎就是编程语言本身!

把十岁小孩“勾”进正文的精准钩子:写代码最怕中途崩溃重来,但现在有人告诉你——根本不需要额外学一堆新东西,你本来就用的编程语言自己就能搞定!

长久以来,做复杂业务流程的人都被迫去画一张张任务依赖图。你实际要写的业务逻辑被埋在图里那些节点深处。但Vercel的Workflow SDK告诉你另一条路:你用async/await写的普通代码,本身就已经是一张有向无环图。

抽象语法树就是DAG,软件本身就是DAG。问题从来不是“怎么画图”,而是“怎么让图自己从代码里长出来”。


画了十年流程图,代码反而更难写了!

Apache Airflow开创了工作流引擎的经典范式。你用一个Python文件描述任务和依赖,调度器按图执行。这套方法统治了数据管道领域好多年。但有个问题一直没人好好解决——你的业务逻辑是写在节点里面的,而节点之间的连线才是引擎真正关心的东西。写代码的人被迫把心思花在“怎么连”上,而不是“做什么”上。

Temporal的出现改变了一些事情。它让你写看起来像普通顺序代码的东西,引擎在底层做持久化。你不用再画DAG图了,控制流就是你的代码本身。这听起来像梦想成真了对吗!

但事情没那么简单。Temporal虽然解决了“画图”的问题,却带来了另一堆麻烦。你想在自己电脑上跑通一个Temporal demo,得先搞定:Frontend服务、History服务、Matching服务、Worker服务,再加一个Cassandra或Postgres或MySQL数据库,还得配置分片。这些服务每个都得自己部署和维护。你的代码自己不执行,得靠Worker轮询服务器来跑。这意味着你还得管一个Kubernetes集群。你得自己处理扩缩容、重启、构建部署流水线。Worker跟控制平面之间还得配mTLS加密。

Datadog自托管Temporal超过四年,从几个集群扩展到几十个,过程中经历了公司级别的计算中断、集群配置错误、分布式系统扩展困难。他们遇到的麻烦“充满艰难的教训和高风险事件”。这不是小公司的烦恼,是头部监控公司都在踩的坑。

这就怪了。一个号称让你“写普通代码”的框架,部署起来却需要一整支基础设施团队。

改一行代码,在跑的工作流就炸了

部署只是第一道坎。真正的噩梦在你改代码的时候才开始。

Temporal的工作流靠事件回放来保证持久化。你在代码里加了一个新步骤,但那些还在跑的旧工作流回放历史事件时,会遇到根本不存在的分支。结果就是非确定性错误,整个工作流直接崩溃。

Temporal的官方解法是一套Patching API。你用patched()或者GetVersion()在代码里做版本分支。新工作流走新逻辑,旧工作流继续走旧逻辑。等旧工作流全部跑完,你再删掉旧分支。

听起来合理对吗!但实际写起来是什么样?你的工作流代码慢慢长满版本标记。一个变更加一个if,两个变更加两个if。改过十几次之后,代码变成了一团版本号的荆棘丛。你想删掉一个旧版本分支,得确认所有相关工作流都已经跑完退出保留期。这个过程可能要等好几天甚至几周。

这还没完。Temporal的Worker版本控制直到2025年9月才发布公开预览版。在那之前,滚动部署时Worker节点逐渐从旧版本切到新版本,正在跑的工作流可能撞上新代码然后报错。官方文档承认这个过程“本质上不安全”。

一个工作流引擎,连改代码都不能安全地改。这叫什么“持久执行”?

信号、查询、更新——三个词把人搞晕了

Temporal有三个独立的原语用来跟运行中的工作流交互:信号是单向的,发了就不管;查询是只读的,不能阻塞;更新是同步的,要等确认。每个都有自己的规则和使用场景。

Temporal官方文档自己都承认:信号和更新处理起来“很棘手”,因为三类不同的并发问题,写阻塞式的消息处理程序“并不总是容易的”,而且“很快就变得复杂,很难做到类型安全”。

你给朋友演示Temporal,光解释这三个东西的区别就得花二十分钟加一块白板。信号是fire-and-forget的,查询不能改状态,更新是同步的但要等worker确认。什么时候用哪个?得看场景。场景一复杂,连写的人自己都搞不清。

一个开发者工具,如果它的核心概念需要白板才能讲清楚,那它就已经输了。

不要编排服务器,要编排代码

Workflow SDK走了完全不同的路。它的核心主张只有一句话:你的编程语言本身就是最好的工作流引擎。

你写一个"use workflow"标记的异步函数,里面全是普通的awaittry/catchPromise.all、循环和条件判断。需要做外部调用(比如调Stripe API)的地方,加一个"use step"标记。编译器读这两个指令,自动把代码拆成工作流和步骤两个bundle。

整个流程就是普通TypeScript代码,没有任何YAML文件、没有专门的DSL、没有额外的状态机要学。你的控制流就是你的DAG,代码怎么写,流程就怎么跑。

Workflow SDK的GitHub仓库已经积累了超过2200颗星,有504个发布版本,被470个项目依赖。从2025年10月发布beta以来,Workflows处理了超过1亿次运行和超过5亿个步骤,覆盖超过1500家客户,每周npm下载量超过20万次。

这些数字背后是一个事实:开发者受够了在基础设施的泥潭里打滚。

你的数据库就是你的编排引擎

Workflow SDK的另一个反常识设计是:它没有自己的编排服务器。

DBOS最早证明了这条路走得通。它是一个开源库,唯一依赖就是Postgres。所有工作流状态都自动持久化到数据库里,程序崩溃后重启就能从上一个完成的步骤继续跑。不需要单独的工作流服务器,不需要额外的任务队列系统。

Workflow SDK把这个思路推得更远。它的后端是可替换的——Postgres、Cassandra、文件系统、Turso、Durable Objects都可以做持久化层。队列可以用Vercel Queues、SQS、Cloudflare Queues。所有组件都通过一个叫World的统一接口来交互。

连Vercel自家的托管后端都“只是一个CRUD API”。它不做任何计算和编排,所有工作流逻辑都跑在开源的客户端库里。数据格式也不是专用的,你想换哪块就换哪块。

一个工作流引擎,它的“服务器”只是一个数据库API。这听起来像是把复杂的东西变简单了——但事实就是,复杂的东西本来就不该那么复杂。

版本问题不靠补丁靠固定

Workflow SDK解决版本问题的办法跟所有人都不一样。它不让你在代码里写版本分支。每个运行都固定在你启动它时那个具体的部署版本上。你改了代码,新运行用新代码,旧运行继续用旧代码。永远不会有“旧运行撞上新代码”的情况。

这个方案在Vercel上实现起来很自然,因为Vercel本来就长期保留不可变的部署产物。官方Postgres版本还没有实现这个路由机制,但社区已经有人做出来了。Platformatic团队在Kubernetes上实现了版本安全的持久工作流。

这个设计的妙处在于:它把版本管理的复杂度从“每个开发者都要会写版本补丁”转移到了“基础设施提供者去实现固定机制”。前者是成百上千个开发者各自痛苦,后者是几个平台作者集中解决一次。

一个好框架的标准就是:把硬问题往上推,不让每个用户各自解决一遍。

步骤应该像函数调用一样免费

Workflow SDK还有一个野心:让步骤调用的开销降到几乎为零。

目前每次调用一个步骤都涉及网络请求和队列往返,用来可靠地提交结果。这个开销在正确性上是必要的,但它破坏了“分布式计算应该像函数调用”的承诺。开发者会开始算计“这个函数值不值得做一个步骤”,开始考虑颗粒度问题。

理想状态是:你随便拿一个现有代码库里的函数,加上"use step",一切照常工作,没有序列化限制,没有性能损失。Workflow SDK已经在朝这个方向走了。v5版本已经实现了最高5倍的性能提升,API没有任何变化。Nitro v3的原生集成让步骤间延迟降低了大约40%。zstd压缩让大payload的存储和读写都更快。

如果任何一个开发者都能用两个词把一个普通函数变成具有微服务级别性能、网络能力、可观测性和可用性的东西——那会彻底改变我们写代码的方式。

但这件事还没完

Workflow SDK在理念上迈出了一大步,但落地还有挑战。步骤开销虽然在大幅降低,但离“完全免费”还有距离。官方Postgres世界的版本固定机制还没实现。社区世界能不能跟上官方World接口的演进速度,也是个未知数。

最有趣的一个细节是:Workflow SDK的v5 beta在性能测试中实现了最高5倍提升,但团队在GitHub讨论里承认——v6会“进一步推进”并且“让第三方世界同样快”。也就是说,当前的速度提升主要针对特定后端,通用方案还在路上。

一个宣称“后端可替换”的框架,性能优化却先绑定在特定后端上。这个矛盾怎么解决,值得继续看。

但无论如何,一个基本事实已经改变了:以前你做一个持久化工作流,得先部署一整套基础设施。现在你只需要写TypeScript,加两个指令,用你已经有的数据库。

回不去了。