Referencia: Flota de Workers
Una flota de workers de referencia para Node.js 24: procesadores BullMQ, idempotencia, monitoreo de colas de mensajes fallidos (DLQ) y concurrencia consciente del pool, emparejada con Referencia: API SaaS B2B.
Busca en todas las páginas de la documentación
Una flota de workers de referencia para Node.js 24: procesadores BullMQ, idempotencia, monitoreo de colas de mensajes fallidos (DLQ) y concurrencia consciente del pool, emparejada con Referencia: API SaaS B2B.
Tarjeta de receta de referencia rápida.
La API publica un trabajo → Redis (BullMQ) → pod(s) de worker → Postgres + HTTP saliente
↓ fallos
Cola DLQ + PagerDuty// Estándar de sobre de trabajo
type JobEnvelope<T> = {
idempotencyKey: string;
tenantId: string;
traceparent?: string;
payload: T;
};// src/workers/order-email.worker.ts
import { Worker, Queue } from "bullmq";
import IORedis from "ioredis";
const connection = new IORedis(process.env.REDIS_URL!, { maxRetriesPerRequest: null });
export const orderEmailQueue = new Queue("order-email", { connection });
const worker = new Worker(
"order-email",
async (job) => {
const { idempotencyKey, tenantId, payload } = job.data;
const done = await redis.set(`idem:${idempotencyKey}`, "1", "EX", 86400, "NX");
if (!done) {
job.log("duplicate skipped");
return;
}
await sendEmail(tenantId, payload);
},
{
connection,
concurrency: 5, // pool max 20 en el worker; la API usa 10
},
);
worker.on("failed", async (job, err) => {
if (job && job.attemptsMade >= 3) {
await dlq.add("failed", { original: job.data, error: String(err) });
}
});// src/main-worker.ts - apagado elegante
import { orderEmailWorker } from "./workers/order-email.worker";
async function shutdown(signal: string) {
console.info({ msg: "shutdown", signal });
await orderEmailWorker.close();
process.exit(0);
}
process.on("SIGTERM", () => shutdown("SIGTERM"));| Métrica | Alerta |
|---|---|
bullmq_queue_waiting | > 1000 durante 10m |
bullmq_dlq_depth | > 0 durante 15m |
job_duration_p95 | > 30s |
pg_pool_waiting | > 0 durante 5m en el worker |
pool max en el worker = 20
concurrencia = 5 (no 20 - los trabajos hacen 2-4 consultas cada uno)
API pool max = 10 (despliegue separado)max_connections de Postgres{tenantId}:{event}:{entityId} por ejemplo acme:order-email:ord_123processed_jobs para finanzas1. La alerta se dispara por la profundidad de la DLQ
2. El personal de guardia inspecciona los primeros 5 trabajos en Bull Board
3. Corrige la causa raíz (error de plantilla, 403 del proveedor)
4. Reproduce la DLQ en la cola principal en lotes de 50
5. Post-mortem si los correos electrónicos de los clientes incumplieron el SLAworker.worker.close() al apagar (ver Apagado elegante).Versiones de la pila: Esta página fue escrita para Node.js 24.18.0 (LTS activa), npm 10+, TypeScript 5.6+, Express 5, Fastify 5 y NestJS 11.
Revisado por Chris St. John·Última actualización: 16 jul 2026