Skip to content

Notifications on BullMQ

@warlock.js/notifications sends .queue() deliveries through a QueueDispatcher in NotificationConfig.queue. @warlock.js/notifications ships one backed by BullMQ, bullmqQueue(), which lazily loads @warlock.js/queue (an optional peer) the first time .queue() runs.

src/config/notifications.ts
import { type NotificationConfig, bullmqQueue, mailChannel } from "@warlock.js/notifications";
const config: NotificationConfig = {
channels: { mail: mailChannel() },
queue: bullmqQueue({
attempts: 3,
backoff: { type: "exponential", delay: 5000 },
}),
};
export default config;

Configure the queue itself too (connection, etc. — see Configuration). No separate worker is needed: a queued delivery is an ordinary job (warlock.notifications.deliver) processed by the same workers queueConnector() starts.

await orderShipped.queue(user, { order }); // enqueued, delivered by a worker
await orderShipped.queue(user, { order }, { delay: "10m" }); // delivered in 10 minutes
  • The job carries the already-rendered payload and resolved route; the handler looks up the channel by name in that worker process’s own notifications config and calls channel.send.
  • SendOptions.delay: a plain number is seconds (notifications’ convention), a string is a duration ("10m", "2h") — the dispatcher converts both to the queue’s millisecond delay.
  • channel.send throwing is retried per the dispatcher’s attempts / backoff, then lands in failedJobs() once exhausted.
  • A channel name missing from the worker’s notifications config fails the delivery immediately, with no retries — this usually means the worker process has a different channels config than the process that queued it.

| Option | Default | Notes | |---|---|---| | queue | the default queue | which queue deliveries run on | | attempts | queue.defaultJobOptions.attempts, else 1 | | | backoff | — | fixed or exponential |

@warlock.js/queue itself gains no dependency on @warlock.js/notifications — it only ships the job primitives bullmqQueue dispatches through.