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.