Skip to main content

Background Jobs (BullMQ)

The queue module provides Redis-backed background job processing using BullMQ. It is registered as a global module so any other module can inject queues without importing it explicitly.

Registered Queues

Queue NameConstantPurpose
emailEMAIL_QUEUETransactional email delivery via Resend
webhookWEBHOOK_QUEUEWebhook event processing

Configuration

The module is registered via QueueModule.register() in the application root:

import { QueueModule } from "./modules/queue";

@Module({
imports: [
QueueModule.register(),
// ...
],
})
export class AppModule {}

Redis Connection

The module reads the REDIS_URL environment variable and parses it into host, port, password, database, and TLS settings. If REDIS_URL is not set, it falls back to localhost:6379.

Default Job Options

All queues share these defaults:

OptionValue
attempts3
backoffExponential, 1 second base delay

This means a failed job is retried up to 3 times with delays of 1s, 2s, and 4s.

Creating a Job Processor

To process jobs from a queue, create a processor class that extends WorkerHost:

import { Processor, WorkerHost } from "@nestjs/bullmq";
import { Job } from "bullmq";
import { EMAIL_QUEUE } from "../queue/constants";

@Processor(EMAIL_QUEUE)
export class EmailProcessor extends WorkerHost {
async process(job: Job): Promise<void> {
// Handle the job
}
}

Register the processor in the corresponding module's providers array.

Adding a New Queue

  1. Add a constant to apps/api/src/modules/queue/constants.ts:
export const MY_QUEUE = "my-queue";
  1. Register it in QueueModule.register() by adding to the BullModule.registerQueue call:
BullModule.registerQueue(
{ name: EMAIL_QUEUE },
{ name: WEBHOOK_QUEUE },
{ name: MY_QUEUE },
),
  1. Inject the queue in your service:
import { InjectQueue } from '@nestjs/bullmq';
import { Queue } from 'bullmq';

constructor(@InjectQueue('my-queue') private readonly myQueue: Queue) {}

Graceful Fallback

When Redis is not available, BullMQ connection attempts will fail. Services that depend on queues (like EmailService) use @Optional() injection to detect this and fall back to synchronous in-process handling. See the Email module for an example of this pattern.

Environment Variables

REDIS_URL=redis://localhost:6379