cl-pipelines crash-safe. Every checkpoint is a small serialized record stored by your StorageAdapter. When a phase completes or explicitly saves progress, the library writes a new checkpoint. When the pipeline finishes, it clears it. At no point is in-progress state held only in memory — if your process dies, the data survives in storage.
Checkpoint shape
nextPhase field is the lookup key advancePhase uses to find the right Phase object. If you rename a phase in your code after a checkpoint has been written, the resume will fail with a “phase not found” error — handle renames carefully in production.
When checkpoints are written
When
ctx.saveState(state) is called, nextPhase is set to the current phase name — not the next one. This ensures that a crash re-enters the same phase, not skips ahead to the next one.When checkpoints are cleared
The checkpoint is set tonull and status is set to "complete" only when a phase returns { kind: "done" }. In all error cases — thrown exceptions or { kind: "error" } returns — the checkpoint is preserved so you can resume later.
Resume semantics
When you callrunPipeline on a job that already has a checkpoint, retryMode determines what happens:
- resume (default)
- full
resolveStartPhase returns checkpoint.nextPhase. The existing checkpoint state is loaded and passed to the phase as ctx.checkpoint.state. Only the phase that was running (or waiting to run) at the time of the crash re-executes.Resume example: wiring a retry button
The following shows how you might hookrunPipeline to a “Retry” button in your application. Because runPipeline only writes to storage and enqueues a scheduler event, it’s safe to call directly from a UI action or mutation handler:
Inspecting checkpoints in tests
The in-memory storage adapter’s_inspect() method lets you examine checkpoint state directly in tests: