@spfn/workflow chains Jobs from @spfn/core into
pipelines — sequential with .pipe(), parallel with .parallel(),
results type-inferred between steps. Every execution is persisted to PostgreSQL, so a
failed run can resume from the failure point or roll back through each step's
compensate function.
A workflow is a pipeline of Jobs, and each Job stays an independent
unit of work — unaware of the steps around it, reusable across workflows. A new process is
a new combination of existing steps, not new code. Data never flows implicitly: every step
gets an explicit mapper over ctx.input and ctx.results, with
previous outputs type-inferred, and only registered workflows can be executed.
The engine writes every execution to
spfn_workflow.executions and every step to
spfn_workflow.step_executions — status, output, error, timestamps. Because
the database records exactly which steps completed, failure has two precise answers
instead of one blunt one. With .resumable(true), retry skips the
completed steps and restarts at the failure point. With .rollback(true), the
engine runs the compensate function of each completed step in reverse order —
and keeps going even if one compensation fails. Outputs past the 1MB threshold move to
external storage, leaving a $ref in the row.
Chainable definition — TypeBox input schema, .pipe, .parallel, .build.
Named branches run together; results referenced by key downstream.
Retry skips completed steps and restarts from the failure point.
compensate functions of completed steps, executed in reverse order.
defineWorkflowRouter — the engine initializes when the server starts.
start, get, getStepOutput, list, retry, cancel, subscribe.
.notify on started/completed/failed — console built in, custom via @spfn/notification.
Step output past 1MB goes to external storage, a $ref stays in the row.