Skip to article

Resume durable operations

Persist a remote identifier and resume read-only polling without silently submitting duplicate work.

On this page

Persist intent, then the remote ID

runDurableOperation coordinates an application-supplied submit callback and read-only poll callback. It saves a submitting intent before dispatch, saves the returned remote ID, and resumes that same ID on later invocations. It is not a managed background worker or a provider-specific job adapter.

durable.ts · fixture
import {
  createMemoryCheckpointStore, runDurableOperation,
} from '@belweave/search-sdk/durable';

const store = createMemoryCheckpointStore(); // Tests only; not disk persistence
const options = {
  key: 'example-job',
  operation: 'example.fixture',
  inputFingerprint: 'fixture-v1',
  store,
  submit: async () => ({ remoteId: 'fixture-job-1' }),
  poll: async () => ({ state: 'completed' as const, value: { ok: true } }),
};
const first = await runDurableOperation(options);
const resumed = await runDurableOperation(options);
console.log(first.value, resumed.resumed); // { ok: true }, true

Choose a checkpoint store

StoreBoundary
createMemoryCheckpointStore()Process-local tests; does not survive exit.
createFileCheckpointStore({ directory })Explicit Node-only subpath /durable-node; pre-existing absolute private local directory.
Custom CheckpointStoreMust implement atomic compareAndSet across every writer and defensive snapshots.

The local file store uses exclusive per-key locks, atomic rename, and file/directory fsync. A crashed writer's lock is not stolen automatically. Stop writers and reconcile before removing stale locks. It is designed for trusted local filesystems, not distributed consensus.

Fail closed on ambiguous submission

operation and inputFingerprint bind a checkpoint to the caller's intended work. Fingerprints and keys must be opaque and secret-free. Result checkpoints are JSON snapshots; they can contain sensitive provider data, so control storage access and retention.

After independently verifying the remote job belongs to the saved intent, call attachDurableRemoteId({ store, key, operation, inputFingerprint, remoteId }). It requires the matching submitting checkpoint and uses compare-and-set to attach the identifier. A later run can resume read-only polling. The helper cannot independently verify provider ownership.

Bound each invocation

Defaults are a 30-second invocation deadline, one-second poll interval, and 100 polls. Cancellation or deadline expiry while polling and poll-limit failure retain the saved remote identifier for later resumption. Submission interruption instead requires ambiguity reconciliation. Polling is explicit, bounded, and separate from remote cancellation.