Skip to content

Install and quickstart

  1. Install the package

    Terminal window
    npm install durability
  2. Create a SQLite Durable Object migration

    {
    "migrations": [
    { "tag": "v1", "new_sqlite_classes": ["EmailJobs"] }
    ]
    }
  3. Define typed handlers

    import {
    createDurability,
    NonRetryableError,
    type DurableHandler,
    } from 'durability';
    const handlers = {
    sendEmail: (async ({ id, payload, attempt, signal }) => {
    const response = await fetch(payload.url, {
    method: 'POST',
    headers: {
    'Content-Type': 'application/json',
    'Idempotency-Key': id,
    },
    body: JSON.stringify(payload.message),
    signal,
    });
    if (response.status === 400) {
    throw new NonRetryableError('Email request is invalid');
    }
    if (!response.ok) {
    throw new Error(`Email request failed: ${response.status}`);
    }
    return { attempt, messageId: await response.text() };
    }) satisfies DurableHandler<
    { url: string; message: string },
    { attempt: number; messageId: string }
    >,
    };
  4. Create Durability and delegate the alarm

    export class EmailJobs extends DurableObject<Env> {
    private readonly durability = createDurability(this.ctx, handlers);
    send(userId: string, payload: Parameters<typeof handlers.sendEmail>[0]['payload']) {
    return this.durability.sendEmail({
    id: `welcome:${userId}`,
    payload,
    });
    }
    alarm(info?: AlarmInvocationInfo) {
    return this.durability.alarm(info);
    }
    }
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;
}

The completed value is inferred from the handler return type. Looking up an ID owned by another operation throws DuplicateDurableCallError instead of returning a value with the wrong type.

createDurability applies package migrations and stores operations in durability_calls, named schedules in durability_alarms, and migration history in durability_migrations.

import { migrateDurability } from 'durability';
migrateDurability(this.ctx, 'durability_0001_create_calls');
migrateDurability(this.ctx, null);