One-page lookup for the three primitives every BullMQ system is built from: Queue, Worker, Job. Cite: Queues, Workers, Jobs, Connections.
Producer ──add()──▶ Queue (Redis list) ──pull──▶ Worker ──▶ done | failed
▲
stored as Job objects
maxRetriesPerRequest: null on the ioredis instance. BullMQ uses blocking Redis commands; without this, ioredis throws BREADONLY / Connection is closed. under failover.
import IORedis from 'ioredis';
const connection = new IORedis('redis://localhost:6379', {
maxRetriesPerRequest: null,
});
Pass the same connection to every Queue and Worker in that process, or reuse BullMQ's default.
import { Queue } from 'bullmq';
const emailQueue = new Queue<EmailPayload>('email', { connection });
await emailQueue.add('send-welcome', { to: '[email protected]', userId: 42 });
| Method | Use |
|---|---|
add(name, data, opts?) | Enqueue one job. Returns Promise<Job>. |
addBulk([{name, data, opts}, ...]) | Enqueue many in one round-trip. |
getJob(id) | Inspect a job by id. |
getWaiting/Active/Completed/Failed/Delayed() | List jobs in each state. |
obliterate() | Wipe the queue entirely (no undo). |
import { Worker, Job } from 'bullmq';
new Worker<EmailPayload>('email',
async (job: Job) => {
await job.updateProgress(50);
await sendEmail(job.data.to);
return { ok: true };
},
{ connection, concurrency: 5 },
);
completed, value stored on job.returnvalue.failed, retried automatically if attempts > 1.(job, token?, signal?). Use signal for cooperative cancellation.worker.on('completed', (job, returnvalue) => {});
worker.on('failed', (job, err, prev) => {}); // job may be undefined
worker.on('progress', (job, progress) => {});
worker.on('error', err => console.error(err)); // MANDATORY or worker stalls
import { QueueEvents } from 'bullmq';
const qe = new QueueEvents('email', { connection });
qe.on('completed', ({ jobId, returnvalue }) => {});
| Field | What it holds |
|---|---|
job.id | Unique id (auto unless you pass one in options). |
job.name | The name given to queue.add. |
job.data | Typed payload. This is your contract with the producer. |
job.opts | Attempts, backoff, delay, priority, repeat, jobId… |
job.attemptsMade | How many tries so far (1-based after first run). |
job.progress | Latest value passed to updateProgress. |
job.returnvalue | Whatever the processor returned. |
add() optionsawait queue.add('resize', { path }, {
attempts: 5,
backoff: { type: 'exponential', delay: 1000 },
delay: 60_000, // ms before worker may pick it up
priority: 1, // lower = higher priority
removeOnComplete: 1000,
removeOnFail: 5000,
jobId: `resize-${path}`, // makes it idempotent on retry
});
npm install bullmq ioredis
# Redis ≥ 2.8.18 running on localhost:6379
Next lessons: retries & backoff, delayed/repeatable jobs, flows, rate-limiting, graceful shutdown.