Malla文档

工作流引擎

execSteps,浏览器、同步和持久化适配器,以及重放规则。

开发者指南

客户端和服务端工作流共享同一种 JSON 格式和同一个解释器 @malla/engine。唯一不同的是运行每个步骤的适配器。工作流是解释执行的,从不编译:发布时存储一个不可变的版本,由一个 runner 为所有站点提供服务。

三种适配器

浏览器已发布站点和画布预览。sleep 是一个定时器;waitForEvent 不可用。
同步在 runner 内联运行,用于端点和短任务。在进程内重试;持久化步骤会抛出 DurableRequired。
持久化Cloudflare Workflows(SiteWorkflow):sleep、waitForEvent、带退避的重试、重放。
ts
interface StepAdapter {
  do<T>(name: string, retry: RetryPolicy | undefined, fn: () => Promise<T>): Promise<T>
  sleep(name: string, duration: string): Promise<void>
  waitForEvent(name: string, opts: { type: string; timeout?: string }): Promise<unknown>
}

步骤格式

ts
interface WorkflowStep {
  id: string
  action: string                         // core.<name> or <pluginId>.<name>
  params?: Record<string, unknown>       // values may be Bindings at any depth
  branches?: Record<string, WorkflowStep[]>  // then/else, body, try/catch, cases, lanes a…h
  disabled?: boolean
  retry?: { limit: number; delay?: string; backoff?: 'constant' | 'linear' | 'exponential' }
}

每个步骤的结果存储在 steps[id] 中。控制流把步骤列表嵌套在 branches 中。当且仅当服务端工作流包含一个已启用的 core.sleep 或 core.waitForEvent 时,它才是持久化的。

重放规则

Cloudflare Workflows 会重新执行代码,并为已完成的步骤返回缓存的结果,因此:

  • 步骤名称是确定性的路径 <branch>/<loop index>/<step>,这样循环和分支能正确重放;并行通道会加上 <name>/<lane>/<step>。
  • 步骤之外的一切都是确定性的;fn.now() 在步骤内部运行。
  • 工作流版本固定在运行参数中,因此进行中的运行绝不会看到之后的编辑。
  • 保存在历史中的步骤结果,每个最多 16 KB。

Runner 接线

text
apps/runner (Worker)
  ├─ POST /run/:siteId/:workflowId     test and editor runs (api)
  ├─ ALL  /api/*                       endpoints + webhooks (sites)
  ├─ Workflows binding  → SiteWorkflow   durable runs
  ├─ Durable Objects    → SiteScheduler (cron alarms), RunStream (live test runs),
  │                       SiteDatabase (tables, visitors)
  └─ Worker Loader      → runJs isolates (no bindings, no secrets)

已发布的服务端工作流连同其 HTTP 路由和定时计划,存放在 KV 的 wf:<environment>:<siteId> 下。每次发布都会重新安排站点的定时任务。

限制

客户端服务端
每次运行的步骤数2001,000,按套餐可能更低
嵌套深度88
循环次数1,0001,000
每步重试次数—5
同步运行超时—30 秒
并行通道 / switch 分支8 / 328 / 32