Skip to content

Reliability and operations

Defaults can be overridden globally and per method:

const durability = createDurability(this.ctx, handlers, {
alarmConcurrency: 10,
backgroundConcurrency: 20,
alarmHandoffMs: 14 * 60_000,
attemptTimeoutMs: 60_000,
retries: {
maxAttempts: 5,
jitter: 'equal',
},
methods: {
sendEmail: {
attemptTimeoutMs: 30_000,
retries: {
maxAttempts: 10,
jitter: 'full',
},
},
},
});

Retry jitter supports none, equal, and full. A timed-out attempt aborts its attempt-scoped AbortSignal and follows the normal retry policy. APIs that honor the signal stop promptly; arbitrary JavaScript cannot be forcibly terminated.

Attempts become terminal after maxAttempts. Use NonRetryableError for a permanent error that should fail immediately:

import { NonRetryableError } from '@repo/durability';
if (response.status === 400) {
throw new NonRetryableError('Recipient permanently rejected');
}

The package also recognizes NonRetryableError values created by cloudflare:workflows.

Each timer or alarm claim reads at most 100 due calls:

  • Alarm calls run with alarmConcurrency.
  • Background calls run with backgroundConcurrency.
  • One Durability instance keeps at most one background timer active.
  • Additional due work schedules another pass instead of creating an unbounded scan.

Cloudflare limits alarm invocation wall time. By default, Durability hands pending work to an immediate alarm before that limit:

createDurability(this.ctx, handlers, {
alarmHandoffMs: 14 * 60_000,
});

The next alarm attaches to the same in-memory promise when the object remains alive. After eviction or restart it reconstructs the persisted pending call and may execute it again.

Use a durability-enabled Durable Object as a coordinator for sagas or two-phase operations:

  1. Persist coordinator progress.
  2. Give every participant a stable, step-specific operation ID.
  3. Let participant Durability instances deduplicate retried steps.
  4. Record terminal failure and define compensation when a partial operation must be undone.

There is no transaction across Durable Objects. Intermediate states can remain visible until all participants complete.

Completed records are retained indefinitely so IDs stay deduplicated. The helper owns the Durable Object alarm. Route unrelated scheduled work through the same alarm handler rather than replacing the alarm independently.