runPipeline and advancePhase are the two functions at the heart of the execution model. Understanding what each one does — and what it deliberately does not do — helps you reason about crash safety, retry behavior, and how to wire them into your scheduler.
What runPipeline does
runPipeline is intentionally thin. It does not execute any phase directly. When you call it, the library:
- Resolves the starting phase (from
initialPhase, the first element ofphases, or the existing checkpoint’snextPhaseif resuming) - Writes
status: "running"and the initial checkpoint to yourStorageAdapter - Calls
scheduler.scheduleAdvance(jobId, 0)to enqueue the first phase execution
runPipeline is safe to call from a web request handler or UI action — it returns quickly and defers all execution to the scheduler.
What advancePhase does
advancePhase is the worker function. Your scheduler calls it once per phase. It:
- Reads the checkpoint via
storage.getJob(jobId) - Finds the matching
Phasebycheckpoint.nextPhase - Calls
phase.run(ctx)with a fully constructedPhaseContext - Handles the result:
kind: "next"— writes new checkpoint + callsscheduleAdvance(jobId, 0)for the next phasekind: "done"— callssetCheckpoint(jobId, null)+ setsstatus: "complete"kind: "error"or thrown exception — setsstatus: "error"(checkpoint is not modified)
RunPipelineArgs
string
required
Unique identifier for this pipeline run. Use a database row ID, UUID, or any string that’s stable across retries.
Phase<TState>[]
required
Ordered array of phase definitions. Must contain at least one phase. Phase names must be unique within the array.
StorageAdapter<TState>
required
The storage adapter that persists job status, checkpoints, and log entries.
SchedulerAdapter
required
The scheduler adapter that triggers
advancePhase after each phase completes."resume" | "full"
Controls how an existing checkpoint is handled. Defaults to
"resume" when a checkpoint exists. See Retry Modes.TState
required
The starting state passed to the first phase. Used as-is on a fresh run; ignored on
"resume" (checkpoint state takes precedence).string
Override which phase runs first. Defaults to the name of
phases[0].Full example
The following example runs a two-phase document processing pipeline end-to-end using the in-memory adapters:Crash recovery
If your process dies whileadvancePhase is running, the checkpoint still holds the last safe state (either from the previous phase or the last ctx.saveState() call within the current phase). Re-calling runPipeline with retryMode: "resume" picks up from there. See Checkpoints for the exact write semantics.