Build

Define jobs and durable events

Define durable jobs/events, enable capabilities, and wire request-level transaction context.

Definitions must load before framework bootstrap so workers know which names and consumers they may execute.

import {
  defineDurableEvent,
  defineDurableEventHandler,
  defineJob,
} from "@damatjs/framework";

defineJob("send-welcome-email", async ({ userId }, context) => {
  await mailer.sendWelcome(userId, {
    idempotencyKey: `welcome:${userId}`,
    signal: context.signal,
  });
  return { sent: true };
});

defineDurableEvent("user.created", {
  version: 1,
  maxAttempts: 5,
});

defineDurableEventHandler("user.created", "audit-user", async (user) => {
  await auditUser(user.id);
  return { audited: true };
});

Use stable names. A durable event consumer name is part of its persisted delivery identity, so renaming it creates a different consumer.

Enable services and workers

services: {
  jobs: { queue: "default", concurrency: 4 },
  events: { durable: { concurrency: 4 } },
},
runtime: {
  mode: "all",
  workers: ["jobs", "events"],
},

Run bun run db:migrate after enabling either service. A server process does not run workers. A worker process is headless and must select at least one enabled worker type.