Los flujos de trabajo de cliente y de servidor comparten un único formato JSON y un único intérprete, @malla/engine. Solo cambia el adaptador que ejecuta cada paso. Los flujos de trabajo se interpretan, nunca se compilan: publicar guarda una versión inmutable y un solo runner atiende a todos los sitios.
Tres adaptadores
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>
}
Formato de los pasos
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' }
}
El resultado de cada paso se guarda en steps[id]. El control de flujo anida listas de pasos en branches. Un flujo de trabajo de servidor es durable exactamente cuando contiene un core.sleep o un core.waitForEvent activado.
Reglas de replay
Cloudflare Workflows vuelve a ejecutar el código y devuelve resultados en caché para los pasos ya completados, así que:
- Los nombres de los pasos son rutas deterministas,
<branch>/<loop index>/<step>, para que los bucles y las ramas se reproduzcan correctamente; las ramas en paralelo añaden<name>/<lane>/<step>. - Todo lo que está fuera de un paso es determinista;
fn.now()corre dentro de los pasos. - La versión del flujo de trabajo queda fijada en los parámetros de la ejecución, así que las ejecuciones en curso nunca ven las ediciones.
- Los resultados de los pasos que se guardan en el historial tienen un tope de 16 KB cada uno.
Conexión del runner
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)
Los flujos de trabajo de servidor publicados viven en KV en wf:<environment>:<siteId>, con sus rutas HTTP y sus programaciones cron. Una publicación reprograma los crons del sitio.
Límites
| Cliente | Servidor | |
|---|---|---|
| Pasos por ejecución | 200 | 1.000, menos según el plan |
| Profundidad de anidación | 8 | 8 |
| Iteraciones de bucle | 1.000 | 1.000 |
| Reintentos por paso | — | 5 |
| Tiempo máximo de una ejecución síncrona | — | 30 s |
| Ramas en paralelo / casos de switch | 8 / 32 | 8 / 32 |