BullMQ
BullMQ é a biblioteca de filas com backend Redis que a maioria das equipes Node usa para e-mails, webhooks, processamento de mídia e sincronização em segundo plano.
Busque em todas as páginas da documentação
BullMQ é a biblioteca de filas com backend Redis que a maioria das equipes Node usa para e-mails, webhooks, processamento de mídia e sincronização em segundo plano.
Cartão de referência rápida - pronto para copiar e colar.
import { Queue, Worker } from "bullmq";
import IORedis from "ioredis";
const connection = new IORedis(process.env.REDIS_URL!, { maxRetriesPerRequest: null });
export const reportQueue = new Queue("reports", { connection });
new Worker(
"reports",
async (job) => {
await buildReport(job.data.reportId);
},
{ connection: connection.duplicate(), concurrency: 3 }
);Quando usar isso:
// src/queues/connection.ts
import IORedis from "ioredis";
export function createBullConnection() {
return new IORedis(process.env.REDIS_URL!, {
maxRetriesPerRequest: null,
enableReadyCheck: false,
});
}
// src/queues/reports.ts
import { Queue, Worker, QueueEvents } from "bullmq";
import { createBullConnection } from "./connection";
import { buildReport } from "../services/reports";
const connection = createBullConnection();
export const reportsQueue = new Queue("reports", { connection });
export function startReportWorker() {
const worker = new Worker(
"reports",
async (job) => {
await job.updateProgress(10);
const url = await buildReport(job.data.reportId);
await job.updateProgress(100);
return { url };
},
{
connection: createBullConnection(),
concurrency: 2,
lockDuration: 30_000,
}
);
worker.on("failed", (job, err) => {
console.error({ msg: "job_failed", jobId: job?.id, err: err.message });
});
worker.on("stalled", (jobId) => {
console.warn({ msg: "job_stalled", jobId });
});
return worker;
}
// src/api/reports-route.ts
import express from "express";
import { reportsQueue } from "../queues/reports";
const router = express.Router();
router.post("/", async (req, res) => {
const job = await reportsQueue.add(
"build",
{ reportId: req.body.reportId },
{ attempts: 3, backoff: { type: "exponential", delay: 1000 } }
);
res.status(202).json({ jobId: job.id });
});
export default router;O que isso demonstra:
failed e stalled para visibilidade de operaçõeslockDuration expireconst worker = startReportWorker();
process.on("SIGTERM", async () => {
await worker.close(); // aguarda o job atual por padrão
process.exit(0);
});terminationGracePeriodSeconds do k8s > duração mais longa do jobawait reportsQueue.add(
"nightly",
{},
{ repeat: { pattern: "0 2 * * *" }, jobId: "nightly-report" }
);jobId evita definições repetíveis duplicadas na reimplantacãoimport { FlowProducer } from "bullmq";
const flow = new FlowProducer({ connection });
await flow.add({
name: "invoice-pdf",
queueName: "pdf",
data: { invoiceId },
children: [{ name: "fetch-line-items", queueName: "data", data: { invoiceId } }],
});@bull-board/express atrás de autenticação de administradormaxRetriesPerRequest padrão no worker - quebra o BRPOP. Correção: null nas conexões Bull.stalled.| Alternativa | Use Quando | Não Use Quando |
|---|---|---|
| AWS SQS | Sem operações Redis, nativo da AWS | Precisa de fluxos de jobs complexos sem orquestração adicional |
| pg-boss | Pilha apenas Postgres | Redis já é central |
| Temporal | Sagas de longa duração, tarefas humanas | Fila de e-mail simples |
| RabbitMQ | Existência corporativa AMQP | Equipe não tem apetite por operações Erlang |
BullMQ é o sucessor mantido com melhor TypeScript e desempenho. Novos projetos usam BullMQ.
Divida por domínio e SLO: email, webhooks, media. Evite uma fila gigante.
Comece com 2-5 jobs de I/O. Trabalho limitado por CPU: concorrência de 1 por núcleo após profiling.
Suportado com prefixo e tags de hash por documento BullMQ. Teste failover.
BullModule.registerQueue no módulo API; bootstrap de worker separado importa processadores.
jobId estável em queue.add. Combine com chaves de idempotência no worker.
Opção de limitador de taxa BullMQ por fila protege cotas de fornecedores.
Use Redis Testcontainer; afirme que o job foi concluído e o efeito colateral ocorreu uma vez.
Instrumentação OpenTelemetry bullmq + métricas de profundidade da fila (aguardando, ativo, atrasado).
Alta prioridade inunda baixa - use filas separadas para SLAs escalonados em vez disso.
Versões da Stack: Esta página foi escrita para Node.js 24.18.0 (LTS Ativo), npm 10+, TypeScript 5.6+, Express 5, Fastify 5 e NestJS 11.
Revisado por Chris St. John·Última atualização: 16 de jul. de 2026