跳到主要内容

04. Execution Engine:让图真正转起来

4.1 入口:WorkflowExecute.run()

核心类位于 packages/core/src/execution-engine/workflow-execute.tsrun() 的几个关键动作是:

  1. 设置执行状态为 running
  2. 根据显式 start node 或 workflow 的起始节点确定入口。
  3. 如果指定 destination,反向收集祖先节点形成 runNodeFilter
  4. 为起始节点创建 nodeExecutionStack
  5. createRunExecutionData() 初始化 startData、executionData、resultData。
  6. 进入 processRunExecutionData(),持续消费 stack 并产生新的执行项。

它刻意返回可取消的 PCancelable<IRun>。源码中的注释说明,不能把 run() 改成 async,否则会把可取消对象转换为普通 Promise,正在运行的 execution 无法被正确取消。

4.2 执行栈,而不是递归调用

可以用下面的模型理解推进过程:

栈的好处是执行状态显式化:分支、循环、等待、部分执行和暂停恢复都能通过数据结构表达;代价是不能只看一次函数调用来理解流程,必须追踪 IExecuteDataITaskDataIRunExecutionData 的变化。

4.3 节点上下文是能力边界

节点不直接 import 数据库或 Express request,而是得到某种上下文:

  • ExecuteContext:普通执行、读取输入、节点参数、其他节点数据。
  • TriggerContext / PollContext:注册触发器或轮询。
  • WebhookContext:读取请求、响应模式、等待 webhook。
  • SupplyDataContext:为 AI 根节点提供模型、memory、tool 等供给数据。
  • HookContext:执行生命周期和外部 hook。

这些上下文位于 packages/core/src/execution-engine/node-execution-context。统一的基类负责共享逻辑,具体上下文只暴露当前节点需要的能力,避免把整个运行时对象泄漏给节点。

4.4 错误、取消与等待

执行器要区分三类“不是成功”的结果:

  1. 节点业务错误NodeApiErrorNodeOperationError 等,带节点名和可展示信息。
  2. 平台控制错误:取消、超时、凭证缺失、workflow issues、执行状态冲突。
  3. 可恢复状态:等待外部 webhook、延迟、队列重试,不应被当作最终失败。

生命周期 hooks 会在节点前后、执行开始/结束、错误和等待等时机被调用。packages/core/src/execution-engine/execution-lifecycle-hooks.ts 与 CLI 的 workflow hooks 一起把“执行器核心”和“平台副作用”连接起来。

4.5 旧执行顺序与 v1

WorkflowExecute.isLegacyExecutionOrder() 根据 workflow settings 判断是否使用旧执行顺序。这个兼容层说明 n8n 的工作流 JSON 是长期资产:执行语义升级不能只改算法,还要考虑旧工作流导入、版本字段、节点版本和用户已有 execution 的可重放性。

4.6 设计取舍

执行栈 + 持久化换来了可暂停、可恢复和可观测;代价是每一步都要维护 source data、paired item、run index 和状态。

核心执行器不依赖 HTTP,让同一工作流可以被 CLI、Webhook、队列 worker、单测和部分执行复用;代价是大量 IWorkflowExecuteAdditionalData 接口需要在服务层完成装配。

显式错误类型让 UI 能展示“哪个节点、哪类错误、是否可重试”;代价是错误分类和序列化必须持续维护,任意 throw 都可能损失上下文。