Bull / BullMQ + NestJS — Colas de Tareas Asíncronas
Guía completa de implementación de colas con Bull/BullMQ en NestJS. Cubre configuración,
processors, jobs programados con delay, retry, dead letter queue, monitorización y la
estrategia de migración de Bull (desarrollo local) a Cloud Tasks (producción GCP).
Referencias disponibles
Lee el archivo correspondiente cuando necesites profundidad en un área específica:
references/setup-and-config.md — Instalación, BullModule, Redis, configuración por entorno
references/producers.md — Servicios que encolan jobs: QueueService, addJob, delayed jobs
references/processors.md — Workers: @Processor, @Process, manejo de errores, eventos de cola
references/reminder-pattern.md — Patrón completo de recordatorio de cumpleaños (Algoritmo 3 HADA)
references/notification-pattern.md — Cola de notificaciones FCM con retry y token cleanup
references/cloud-tasks-migration.md — Migración de Bull a GCP Cloud Tasks en producción
Cuándo usar cada referencia
| Tarea |
Referencia |
| Configurar Bull/BullMQ por primera vez en el proyecto |
setup-and-config.md |
| Crear un servicio que añade jobs a la cola |
producers.md |
| Implementar el worker que procesa los jobs |
processors.md |
| Implementar Algoritmo 3 (recordatorios de cumpleaños) |
reminder-pattern.md |
| Implementar envío asíncrono de notificaciones push FCM |
notification-pattern.md |
| Configurar Cloud Tasks para producción en GCP |
cloud-tasks-migration.md |
Reglas críticas (siempre en contexto)
1. Bull para desarrollo, Cloud Tasks para producción
// La lógica del job es la misma; solo cambia el mecanismo de scheduling
// Ver references/cloud-tasks-migration.md para la estrategia de abstracción
2. Jobs idempotentes — deben poder ejecutarse más de una vez sin efectos secundarios
// ✅ Siempre verificar el estado actual antes de ejecutar
async processReminder(job: Job<ReminderJobData>) {
const profile = await this.profileRepo.findById(job.data.profileId);
// Si ya se procesó o fue cancelado, salir silenciosamente
if (!profile || profile.reminderScheduledAt?.getTime() !== job.data.scheduledAt) {
return; // Job obsoleto (fue reprogramado), ignorar
}
await this.sendNotification(profile);
}
3. Un job por (profileId + año) para evitar duplicados de recordatorio
// jobId determinístico: si ya existe, Bull lo reemplaza
const jobId = `reminder:${profileId}:${year}`;
await this.queue.add(jobData, { jobId, delay, removeOnComplete: true });
4. Nunca bloquear el event loop en un processor — todo async/await
// ❌ Operación síncrona larga en processor
@Process('send-notification')
handle(job: Job) {
const result = someSyncHeavyOperation(); // Bloquea el worker
}
// ✅ Todo asíncrono
@Process('send-notification')
async handle(job: Job) {
const result = await someAsyncOperation();
}
5. Retry con backoff exponencial — nunca retry inmediato
await queue.add(data, {
attempts: 3,
backoff: { type: 'exponential', delay: 1000 }, // 1s, 5s, 25s
});
Fuentes y documentación oficial
1---2name: bull-bullmq-nestjs3description: Patrones de colas de tareas asíncronas con Bull/BullMQ en NestJS para producción. Usar PROACTIVAMENTE cuando se trabaje con jobs programados, recordatorios, notificaciones asíncronas, procesamiento en background, o cualquier tarea que no deba ejecutarse de forma síncrona en el ciclo de request/response. Activar siempre que aparezcan las palabras clave: Bull, BullMQ, @BullModule, @Processor, @Process, @OnQueueFailed, addJob, Queue, Worker, jobs, colas, tareas programadas, delayed jobs, recordatorio programado, notificación asíncrona, background job, retry, dead letter queue, o colas con Redis en NestJS. También activar para la transición Bull (desarrollo) → Cloud Tasks (producción GCP).4---5
6# Bull / BullMQ + NestJS — Colas de Tareas Asíncronas
7
8Guía completa de implementación de colas con Bull/BullMQ en NestJS. Cubre configuración,
9processors, jobs programados con delay, retry, dead letter queue, monitorización y la
10estrategia de migración de Bull (desarrollo local) a Cloud Tasks (producción GCP).
11
12## Referencias disponibles
13
14Lee el archivo correspondiente cuando necesites profundidad en un área específica:
15
16- `references/setup-and-config.md` — Instalación, BullModule, Redis, configuración por entorno
17- `references/producers.md` — Servicios que encolan jobs: QueueService, addJob, delayed jobs
18- `references/processors.md` — Workers: @Processor, @Process, manejo de errores, eventos de cola
19- `references/reminder-pattern.md` — Patrón completo de recordatorio de cumpleaños (Algoritmo 3 HADA)
20- `references/notification-pattern.md` — Cola de notificaciones FCM con retry y token cleanup
21- `references/cloud-tasks-migration.md` — Migración de Bull a GCP Cloud Tasks en producción
22
23---
24
25## Cuándo usar cada referencia
26
27| Tarea | Referencia |
28| ------------------------------------------------------ | -------------------------- |
29| Configurar Bull/BullMQ por primera vez en el proyecto | `setup-and-config.md` |
30| Crear un servicio que añade jobs a la cola | `producers.md` |
31| Implementar el worker que procesa los jobs | `processors.md` |
32| Implementar Algoritmo 3 (recordatorios de cumpleaños) | `reminder-pattern.md` |
33| Implementar envío asíncrono de notificaciones push FCM | `notification-pattern.md` |
34| Configurar Cloud Tasks para producción en GCP | `cloud-tasks-migration.md` |
35
36---
37
38## Reglas críticas (siempre en contexto)
39
40### 1. Bull para desarrollo, Cloud Tasks para producción
41
42```typescript
43// La lógica del job es la misma; solo cambia el mecanismo de scheduling
44// Ver references/cloud-tasks-migration.md para la estrategia de abstracción
45```
46
47### 2. Jobs idempotentes — deben poder ejecutarse más de una vez sin efectos secundarios
48
49```typescript
50// ✅ Siempre verificar el estado actual antes de ejecutar
51async processReminder(job: Job<ReminderJobData>) {
52 const profile = await this.profileRepo.findById(job.data.profileId);
53 // Si ya se procesó o fue cancelado, salir silenciosamente
54 if (!profile || profile.reminderScheduledAt?.getTime() !== job.data.scheduledAt) {
55 return; // Job obsoleto (fue reprogramado), ignorar
56 }
57 await this.sendNotification(profile);
58}
59```
60
61### 3. Un job por (profileId + año) para evitar duplicados de recordatorio
62
63```typescript
64// jobId determinístico: si ya existe, Bull lo reemplaza
65const jobId = `reminder:${profileId}:${year}`;
66await this.queue.add(jobData, { jobId, delay, removeOnComplete: true });
67```
68
69### 4. Nunca bloquear el event loop en un processor — todo async/await
70
71```typescript
72// ❌ Operación síncrona larga en processor
73@Process('send-notification')
74handle(job: Job) {
75 const result = someSyncHeavyOperation(); // Bloquea el worker
76}
77
78// ✅ Todo asíncrono
79@Process('send-notification')
80async handle(job: Job) {
81 const result = await someAsyncOperation();
82}
83```
84
85### 5. Retry con backoff exponencial — nunca retry inmediato
86
87```typescript
88await queue.add(data, {
89 attempts: 3,
90 backoff: { type: 'exponential', delay: 1000 }, // 1s, 5s, 25s
91});
92```
93
94---
95
96## Fuentes y documentación oficial
97
98- **BullMQ Docs**: https://docs.bullmq.io/
99- **Bull Docs (legacy, compatible)**: https://github.com/OptimalBits/bull/blob/master/REFERENCE.md
100- **@nestjs/bull Docs**: https://docs.nestjs.com/techniques/queues
101- **BullMQ + NestJS Guide**: https://docs.bullmq.io/patterns/nestjs
102- **GCP Cloud Tasks Docs**: https://cloud.google.com/tasks/docs
103- **Cloud Tasks + NestJS**: https://cloud.google.com/tasks/docs/creating-http-target-tasks
104- **Bull Board (dashboard)**: https://github.com/felixmosh/bull-board
105- **Redis Docs**: https://redis.io/docs/