Skip to main content

Queues

Feature powered by BullMQ

Make your API breathe. Offload slow or bursty work (emails, webhooks, reports, 3rd-party calls) to background jobs—without ceremony.

What this plugin gives you

  • BullMQ power, CrumbJS DX: queues & workers wired in minutes.
  • Jobs as classes: extend Queueable<T> and decorate with @IsQueueable().
  • Auto-discovery: handlers are registered on startup—no manual wiring.
  • Retries, backoff & delays: resilient by default.
  • Concurrency control: tune throughput per worker.
  • Type-safe payloads: generics keep your job data honest.

Great for

  • Transactional emails, webhook fan-out, data exports, cache warming, long-running tasks, and cron-like scheduling.

    Heads-up: you’ll need a reachable Redis server (host/port or auth).

Install

Let's install the plugin, on your api directory run:

bun install @crumbjs/bullmq

Mount

Options

type PluginOptions = {
/** Redis HOST @default '127.0.0.1' */
host: string;
/** Redis PORT @default 6379 */
port: number;
/** Redis USERNAME @default undefined */
user?: string;
/** Redis PASSWORD @default undefined */
pass?: string;
/**
* Amount of jobs that a single worker is allowed to work on in parallel.
* @default 10
*/
concurrency: number;
};
import { App } from "@crumbjs/core";
import { bullmqPlugin } from "@crumbjs/bullmq";

/* options are optional */
const app = new App();

app.use(bullmqPlugin(options));
app.serve();

Define a queueable

Create a class that extends Queueable and decorate it with @IsQueueable() and define how to handle it @IsQueueable() decorator register the event type and event handler at api startup.

import { IsQueueable, Queueable } from "@crumbjs/bullmq";

@IsQueueable()
class WelcomeEvent extends Queueable<{ clientId: string }> {
// default options

// void
async handle() {
await EmailService.sendWelcome(this.payload.clientId);
}
}

@IsQueueable()
class SendEmail extends Queueable<{ to: string }> {
/**
* How many times the job will be retried on failure.
* @optional @default 5
*/
public override retries: number = 5;
/**
* Delay in milliseconds before retrying a failed job.
* @optional @default 15000
*/
public override delayOnFailure: number = 15000;
/**
* If true, removes the job when it successfully completes When given a number,
* it specifies the maximum amount of jobs to keep, or you can provide an object specifying max age and/or count to keep.
* @optional @default true (delete job after complete)
*/
public override removeOnComplete: boolean | number = true;
/**
* If true, removes the job when it fails after all attempts. When given a number,
* it specifies the maximum amount of jobs to keep, or you can provide an object specifying max age and/or count to keep.
* @optional @default 100 (keep 100 failed attempts in redis)
*/
public override removeOnFail: boolean | number = 100;

async handle() {
console.log(`Email to ${this.getPayload().to}`);
}
}

Queueing an event anywhere in your Crumbjs Api

import { dispatch } from "@crumbjs/bullmq";

dispatch(new SendEmail({ to: "[email protected]" }));

Easy? right?