Checkpoint
What It Is
The checkpoint surface captures enough information to resume an interrupted DAG run: state, cursor position, lifecycle payload, and optional named store snapshots.
Use this page when a run must survive process exit, browser refresh, worker replacement, human-in-the-loop parking, or any other interruption that should resume deterministically.
How It Works
Checkpoint.capture() builds the record from an execution result and optional named stores. Checkpoint.load() parses a persisted record. Checkpoint.recall() reads from a checkpoint store. restoreState() and restoreStores() apply the payload back to runtime objects before Dagonizer.resume().
The checkpoint does not contain node implementations or dispatcher registries. The host must register the DAG and node IRIs before resuming.
Diagrams, Examples, and Outputs
Checkpoint behavior is easiest to understand through resume examples and store snapshots:
- Reference: Contracts -
CheckpointStore,Snapshottable,StoreSnapshotType,StoreSnapshotEntryType - Reference: Entities -
CheckpointData - Reference: Store -
Store,BaseStore,MemoryStore,StoreError - Reference: Validation -
Validator.checkpoint
What It Lets You Do
The checkpoint reference lets applications capture, serialize, persist, recall, and restore interrupted DAG executions.
@studnicky/dagonizer/checkpoint
The checkpoint module persists and restores in-flight DAG executions. Checkpoint.capture() is the canonical way to build a checkpoint; Checkpoint.load() parses a persisted record back into a Checkpoint instance. Both work whether or not the run uses named stores.
Code Samples
The code below covers checkpoint capture, JSON serialization, persistence, recall, state restore, store restore, and the in-memory checkpoint store.
Import
import { Checkpoint, MemoryCheckpointStore } from '@studnicky/dagonizer/checkpoint';
import type { CheckpointRestoreAdapter, CaptureOptionsType } from '@studnicky/dagonizer/checkpoint';Class: Checkpoint
Checkpoint instances are obtained via Checkpoint.capture() (when saving) or Checkpoint.load() / Checkpoint.recall() (when recalling). Instance methods toJson, persist, restoreState, and restoreStores cover the full lifecycle.
import { Checkpoint } from '@studnicky/dagonizer/checkpoint';import { Checkpoint } from '@studnicky/dagonizer';Checkpoint.capture(dagIri, result, options?)
declare function capture<TState extends NodeStateInterface & NodeStateBase>(
dagIri: string,
result: ExecutionResultType<TState>,
options?: CaptureOptionsType,
): Promise<Checkpoint>;Async factory. Builds a Checkpoint instance from a DAG reference, execution result, and optional named stores. The DAG reference is expanded to the stored DAG IRI; result.cursor is the placement IRI to resume from. Store snapshots run through the shared batch executor; options.execution controls snapshot concurrency, throttle, and timing. The instance exposes .data (the CheckpointData record) and instance methods for the resume side.
Throws DAGError when result.cursor === null (the DAG completed; nothing to resume).
<<< @/../examples/08-checkpoint.ts#captureCalling Checkpoint.capture without a stores option (or with an empty map) writes an empty stores: {} object. The checkpoint loads and resumes cleanly; restoreStores is a no-op when the map is empty.
Checkpoint.load(raw)
const checkpoint: Checkpoint = Checkpoint.load(raw);Parse and validate a raw CheckpointData object (e.g. from JSON.parse) and wrap it in a Checkpoint instance. Throws ValidationError when the raw value fails schema validation.
<<< @/../examples/08-checkpoint.ts#recallCheckpoint.recall(store, key)
const checkpoint: Checkpoint | null = await Checkpoint.recall(store, key);Load a checkpoint from a CheckpointStore by key. Returns null when the store has no entry for the key. Composes store.load + JSON.parse + Checkpoint.load. Throws ValidationError when the stored JSON fails schema validation.
<<< @/../examples/the-archivist/runArchivist.ts#resume-runckpt.toJson()
const json: string = ckpt.toJson();Serialize this checkpoint's data to a pretty-printed JSON string. Symmetric counterpart to JSON.parse + Checkpoint.load.
<<< @/../examples/08-checkpoint.ts#persistckpt.persist(store, key)
await ckpt.persist(store, key);Persist this checkpoint to a CheckpointStore under key. Composes toJson + store.save. Throws when the underlying store throws.
<<< @/../examples/08-checkpoint.ts#persistckpt.restoreState(adapter)
Rehydrate the state from this checkpoint via the supplied adapter. Returns the rehydrated state, DAG IRI, cursor, and execution history. Pass the result to dispatcher.resume.
CheckpointRestoreAdapter<TState> is an interface with a single restore(snap: JsonObjectType): TState method. For a quick inline factory, wrap a plain function with CheckpointRestoreAdapter.wrap(fn) from @studnicky/dagonizer/checkpoint:
const { dagName, state, cursor } = ckpt.restoreState(
CheckpointRestoreAdapter.wrap((snap) => MyState.restore(snap)),
);<<< @/../examples/08-checkpoint.ts#recallThrows ValidationError when ckpt.data.cursor === null.
RecalledCheckpoint<TState> shape:
declare const recalled: RecalledCheckpointType<NodeStateInterface>;
const _state: NodeStateInterface = recalled.state;
const _dagIri: string = recalled.dagName;
const _placementIri: string = recalled.cursor;
const _executedNodes: string[] = recalled.executedNodes;
const _skippedNodes: string[] = recalled.skippedNodes;ckpt.restoreStores(stores, options?)
await ckpt.restoreStores(stores);
await ckpt.restoreStores(stores, options);Populate each named store from the snapshots in this checkpoint. The keys in stores must match the names used when calling Checkpoint.capture. The parameter type is Snapshottable: any object that implements snapshot() / restore(). Store extends Snapshottable, so every Store qualifies; non-KV backends (RDF triple stores, vector indices, append-only logs) participate without implementing get/set/has/delete/update. options.execution controls restore concurrency, throttle, and timing.
<<< @/../examples/the-archivist/runArchivist.ts#resume-runRules:
- Name in checkpoint but absent from the map → throws
DAGErrornaming the missing stores. - Name in the map but absent from the checkpoint → no-op (the store is not restored).
- Matched pairs →
store.restore(snapshot)through the shared batch executor;BaseStore.restorethrowsStoreError(INCOMPATIBLE_SNAPSHOT)on type/version mismatch.
ckpt.data
const data: CheckpointDataType = ckpt.data;The parsed and validated checkpoint record. Serialize with ckpt.toJson().
Interface: CheckpointRestoreAdapter<TState>
declare const adapter: CheckpointRestoreAdapterInterface<{ value: number }>;
const _result: { value: number } = adapter.restore({ key: 1 });Contract for restoring a state instance from a JSON snapshot. Wrap a plain function with CheckpointRestoreAdapter.wrap((snap) => MyState.restore(snap)). Ships from @studnicky/dagonizer/checkpoint.
Interface: CaptureOptionsType
declare const opts: CaptureOptionsType;
const _stores: Record<string, SnapshottableInterface> | undefined = opts.stores;
const _execution: BatchExecutionOptionsType | undefined = opts.execution;| Field | Description |
|---|---|
stores | Named stores to snapshot alongside the state. Any Snapshottable: Store instances, or any non-KV backing that implements snapshot() / restore(). Keys become the names in CheckpointData.stores; the same keys must be passed to restoreStores() on resume. Omit or leave empty for a state-only checkpoint (the CheckpointData.stores field is still written as an empty object {}). |
execution | Batch execution policy for store.snapshot() calls: concurrency, optional throttle, and optional timing. Omit for the default bounded policy. |
Interface: RestoreStoresOptionsType
declare const opts: RestoreStoresOptionsType;
const _execution: BatchExecutionOptionsType | undefined = opts.execution;| Field | Description |
|---|---|
execution | Batch execution policy for store.restore(snapshot) calls: concurrency, optional throttle, and optional timing. Omit for the default bounded policy. |
Interface: RecalledCheckpoint<TState>
declare const recalled: RecalledCheckpointType<NodeStateInterface>;
const _state: NodeStateInterface = recalled.state;
const _dagIri: string = recalled.dagName;
const _cursor: string = recalled.cursor;
const _executedNodes: string[] = recalled.executedNodes;
const _skippedNodes: string[] = recalled.skippedNodes;Type: CheckpointData
Derived from CheckpointDataSchema via json-schema-to-ts.
declare const data: CheckpointDataType;
const _dagIri: string = data.dagName;
const _placementIri: string | null = data.cursor;
const _state: Record<string, unknown> = data.state;
const _executedNodes: string[] = data.executedNodes;
const _skippedNodes: string[] = data.skippedNodes;
const _stores: CheckpointDataType['stores'] = data.stores;stores is a required field. Checkpoint.capture always writes it: as an empty object {} when no stores are passed, or as a keyed map of StoreSnapshotType envelopes when stores are supplied. Any checkpoint payload lacking the field is rejected by Checkpoint.load.
restoreStores treats an empty stores field as a no-op, so state-only checkpoints resume cleanly. Named stores captured at checkpoint time must be supplied by name in the restoreStores map; a name present in the checkpoint but absent from the map throws DAGError.
Type: CheckpointDataSchema
JSON Schema object for CheckpointData.
console.log(CheckpointDataSchema.$id);
// 'https://noocodec.dev/schemas/dagonizer/CheckpointData'Class: MemoryCheckpointStore
In-process CheckpointStore. Stores entries in a Map<string, string> on the instance. Useful for tests, examples, and ephemeral demo flows. Not for production: the map vanishes when the process exits.
import { MemoryCheckpointStore } from '@studnicky/dagonizer/checkpoint';Members
| Member | Description |
|---|---|
save(key, json) | Store json under key. Overwrites existing entries. |
load(key) | Return the JSON string, or null when no entry exists. |
delete(key) | Remove the entry. No-op when missing. |
get size() | Number of entries currently held. Test-only convenience. |
<<< @/../examples/the-archivist/runArchivist.ts#resume-runDetails for Nerds
A checkpoint is only useful with the registered DAG and node IRIs, plus any plugin DAG IRIs, state factories, and stores needed by the saved cursor.
Store snapshots are named. Capture and restore should use stable store names so a persisted checkpoint can rehydrate the intended store instead of a new empty instance.
Related Concepts
- Reference: Contracts -
CheckpointStore,Snapshottable,StoreSnapshotType,StoreSnapshotEntryType - Reference: Entities -
CheckpointData - Reference: Store -
Store,BaseStore,MemoryStore,StoreError - Reference: Validation -
Validator.checkpoint - Checkpoint and Resume - capture and resume flow
- Checkpoint Persistence - durable checkpoint-store implementations
- Shared State - store snapshots and shared state
- Subclassing State - state restore requirements