Setup and execution
-
Add the workspace package
Terminal window pnpm --filter <consumer-workspace> add '@repo/durability@workspace:*' -
Create a SQLite Durable Object migration
{"migrations": [{ "tag": "v1", "new_sqlite_classes": ["ImageJobs"] }]} -
Define typed handlers
import {createDurability,type DurableHandler,} from '@repo/durability';const handlers = {sendEmail: (async ({ id, payload, attempt, signal }) => {const response = await fetch(payload.url, {method: 'POST',body: JSON.stringify(payload.message),headers: { 'Idempotency-Key': id },signal,});return { attempt, messageId: await response.text() };}) satisfies DurableHandler<{ url: string; message: string },{ attempt: number; messageId: string }>,}; -
Create the runtime and delegate the alarm
private readonly durability = createDurability(this.ctx, handlers);alarm(alarmInfo?: AlarmInvocationInfo) {return this.durability.alarm(alarmInfo);}
Enqueue work
Section titled “Enqueue work”Immediate operations are recovered and executed by alarms:
await this.durability.sendEmail({ id: `welcome:${userId}`, payload: { url, message },});Timer-backed background operations use the same handler and result API:
await this.durability.background.sendEmail({ id: `digest:${userId}`, payload: { url, message },});The enqueue promise confirms transactional registration, not handler completion.
Read a typed result
Section titled “Read a typed result”const result = await this.durability.sendEmail.getResult(`welcome:${userId}`);
switch (result.status) { case 'not_found': break; case 'pending': console.log(result.attempt, result.nextAttemptAt, result.lastError); break; case 'failed': console.error(result.error.name, result.error.message); break; case 'completed': console.log(result.result.messageId); break;}Looking up an ID registered for a different operation throws DuplicateDurableCallError, preventing a result from being interpreted as the wrong type.
Schema management
Section titled “Schema management”createDurability migrates to the latest package schema. Migrations are tracked in durability_migrations, and calls live in durability_calls.
import { migrateDurability } from '@repo/durability';
migrateDurability(this.ctx, 'durability_0001_create_calls');migrateDurability(this.ctx, null);