- Update vision, architecture and technical documentation - Update module definitions (PMC-001 to PMC-008) - Update requirements documentation - Add CONTEXT-MAP.yml and ENVIRONMENT-INVENTORY.yml - Add orchestration guidelines and references 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
6.0 KiB
6.0 KiB
| id | title | type | status | date | deciders | tags | project | created_date | updated_date | ||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| ADR-004 | Sistema de Cola de Tareas | ADR | Accepted | 2025-12-08 |
|
|
platform_marketing_content | 2025-12-08 | 2026-01-04 |
ADR-004: Sistema de Cola de Tareas
Fecha: 2025-12-08 Estado: Aceptado
Contexto
La generación de imágenes y otras tareas pesadas requieren:
- Procesamiento asíncrono (no bloquear requests)
- Manejo de prioridades
- Reintentos automáticos
- Monitoreo de estado
- Escalabilidad (múltiples workers)
Decisión
Sistema: Bull/BullMQ con Redis
Usaremos BullMQ (versión moderna de Bull) sobre Redis para gestionar la cola de tareas.
Arquitectura
┌──────────────┐
│ API │
│ Server │
└──────┬───────┘
│ enqueue
▼
┌──────────────┐ ┌──────────────┐
│ Redis │◀───▶│ Worker 1 │──▶ ComfyUI
│ Queue │ └──────────────┘
│ │ ┌──────────────┐
│ │◀───▶│ Worker 2 │──▶ ComfyUI
│ │ └──────────────┘
└──────────────┘ ┌──────────────┐
│ Worker N │──▶ Text Gen
└──────────────┘
Colas Definidas
// Colas por tipo de tarea
const queues = {
'generation:image': {
priority: true,
concurrency: 2, // Limitado por GPU VRAM
},
'generation:text': {
concurrency: 10, // API calls pueden ser paralelos
},
'generation:training': {
concurrency: 1, // Un training a la vez
limiter: {
max: 5,
duration: 86400000, // 5 por día
}
},
'assets:processing': {
concurrency: 5, // Thumbnails, conversiones
},
'notifications:email': {
concurrency: 5,
}
};
Prioridades
enum JobPriority {
URGENT = 1, // Admin/sistema
HIGH = 3, // Usuarios premium
NORMAL = 5, // Usuarios regulares
LOW = 7, // Batch/background
BACKGROUND = 10 // Mantenimiento
}
Configuración de Reintentos
const defaultJobOptions = {
attempts: 3,
backoff: {
type: 'exponential',
delay: 5000, // 5s, 10s, 20s
},
removeOnComplete: {
age: 3600, // 1 hora
count: 1000, // Últimos 1000
},
removeOnFail: {
age: 86400, // 24 horas
}
};
Implementación
Productor (API)
@Injectable()
export class GenerationService {
constructor(
@InjectQueue('generation:image')
private imageQueue: Queue,
) {}
async createImageJob(data: CreateImageJobDto, userId: string) {
const job = await this.imageQueue.add('generate', {
...data,
userId,
tenantId: getCurrentTenant(),
}, {
priority: this.calculatePriority(userId),
jobId: uuid(),
});
return { jobId: job.id };
}
}
Consumidor (Worker)
@Processor('generation:image')
export class ImageGenerationProcessor {
@Process('generate')
async handleGeneration(job: Job<ImageJobData>) {
await job.updateProgress(10);
// Llamar a ComfyUI
const result = await this.comfyui.execute(job.data);
await job.updateProgress(90);
// Guardar resultado
await this.assetsService.createFromGeneration(result);
await job.updateProgress(100);
return { assetId: result.id };
}
@OnWorkerEvent('failed')
onFailed(job: Job, error: Error) {
this.logger.error(`Job ${job.id} failed: ${error.message}`);
// Notificar al usuario si excede reintentos
}
}
Monitoreo con Bull Board
// main.ts
import { createBullBoard } from '@bull-board/api';
import { BullMQAdapter } from '@bull-board/api/bullMQAdapter';
import { ExpressAdapter } from '@bull-board/express';
const serverAdapter = new ExpressAdapter();
createBullBoard({
queues: [
new BullMQAdapter(imageQueue),
new BullMQAdapter(textQueue),
],
serverAdapter,
});
app.use('/admin/queues', serverAdapter.getRouter());
Consecuencias
Positivas
- Desacoplado: API no espera por generación
- Resiliente: Jobs sobreviven reinicios
- Escalable: Agregar workers es trivial
- Observable: Bull Board para monitoreo
- Probado: Bull es muy estable y popular
- Simple: Redis ya lo usamos para cache
Negativas
- Redis es SPOF: Requiere replicación para HA
- Memoria: Jobs grandes consumen RAM de Redis
- Complejidad: Debugging de jobs distribuidos
- Orden: No garantizado estricto (prioridades son best-effort)
Mitigaciones
- Redis Sentinel para alta disponibilidad
- Payloads pequeños (referencias, no datos)
- Logging estructurado con correlation IDs
- Timeouts para evitar jobs colgados
Alternativas Consideradas
1. RabbitMQ
Pros:
- Más features de messaging
- Mejor para pub/sub complejo
Contras:
- Infraestructura adicional
- Más complejo de operar
- No tan integrado con Node
Rechazo: Overkill, ya tenemos Redis
2. AWS SQS
Pros:
- Managed, sin operación
- Escalabilidad infinita
Contras:
- Vendor lock-in
- Sin prioridades nativas
- Costos variables
Rechazo: Preferimos portabilidad
3. PostgreSQL SKIP LOCKED
Pros:
- Sin infraestructura adicional
- Transaccional
Contras:
- Performance limitada
- Sin prioridades elegantes
- Menos features
Rechazo: No escala para alta carga
Referencias
Documento generado por: Requirements-Analyst Fecha: 2025-12-08