# ADR-0002: Procesamiento Asincrono --- id: ADR-0002 type: ADR status: Aceptado created_date: 2026-01-10 updated_date: 2026-01-10 decision_date: 2026-01-10 deciders: ["Tech Lead"] --- ## Estado **Aceptado** --- ## Contexto El procesamiento de video con IA para deteccion de productos: - Toma entre 30 segundos y 3 minutos - Depende de APIs externas (OpenAI, Claude) - Puede fallar por timeout o errores de red - Necesita reintentos y manejo de errores Procesar sincronamente en la request HTTP: - Causaria timeouts - Bloquearia recursos del servidor - Proporcionaria mala experiencia de usuario --- ## Decision Implementar **procesamiento asincrono con Bull/Redis** para: 1. **Job Queue** - Cada video subido crea un job en la cola - Workers procesan jobs en background - Jobs tienen estados: PENDING, PROCESSING, DONE, FAILED 2. **Notificaciones** - Push notification cuando el resultado esta listo - Polling opcional para clientes sin push 3. **Reintentos** - Jobs fallidos se reintentan automaticamente - Backoff exponencial para APIs externas - Max 3 reintentos por job 4. **Monitoreo** - Dashboard de Bull para ver estado de jobs - Alertas por tasa de error alta - Metricas de tiempo de procesamiento --- ## Opciones Consideradas ### Opcion A: Procesamiento Sincrono | Aspecto | Valor | |---------|-------| | Complejidad | Baja | | UX | Mala (esperar 1-3 min) | | Escalabilidad | Baja | | Manejo errores | Dificil | **Descartada:** Inaceptable para UX y escalabilidad. ### Opcion B: AWS SQS + Lambda | Aspecto | Valor | |---------|-------| | Complejidad | Alta | | Escalabilidad | Muy alta | | Costo | Variable | | Vendor lock-in | Alto | **Descartada:** Sobre-ingenieria para MVP, lock-in. ### Opcion C: Bull + Redis (Seleccionada) | Aspecto | Valor | |---------|-------| | Complejidad | Media | | Escalabilidad | Alta | | Costo | Bajo (Redis ya existe) | | Control | Total | **Seleccionada:** Balance ideal para MVP con path de escalamiento. --- ## Consecuencias ### Positivas - **UX fluida**: Usuario no espera, recibe notificacion - **Resiliente**: Reintentos automaticos - **Escalable**: Agregar workers segun demanda - **Observable**: Dashboard, metricas, logs - **Flexible**: Prioridades, delays, dependencias ### Negativas - **Complejidad**: Otro componente (Redis) - **Eventual consistency**: Resultado no inmediato - **Debugging**: Mas dificil seguir el flujo - **Infraestructura**: Redis debe ser HA en produccion --- ## Arquitectura ``` ┌─────────────────────────────────────────────────────────────────┐ │ PROCESAMIENTO ASINCRONO │ ├─────────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ API │───▶│ Queue │───▶│ Worker │───▶│ Notifier │ │ │ │ (NestJS) │ │ (Bull) │ │ (Bull) │ │ (FCM) │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ │ │ │ │ │ │ ▼ ▼ ▼ ▼ │ │ Crear job Redis Procesar IA Push notif │ │ status=PENDING almacena actualizar DB al usuario │ │ jobs status=DONE │ │ │ └─────────────────────────────────────────────────────────────────┘ ``` --- ## Implementacion ### Definicion del Job ```typescript // jobs/inventory-processing.processor.ts @Processor('inventory') export class InventoryProcessor { @Process('process-video') async processVideo(job: Job) { const { sessionId, videoId } = job.data; try { // 1. Actualizar status await this.updateStatus(sessionId, 'PROCESSING'); // 2. Descargar video de S3 const video = await this.s3Service.download(videoId); // 3. Extraer frames const frames = await this.extractFrames(video); // 4. Procesar con IA const detections = await this.iaService.detectProducts(frames); // 5. Consolidar resultados const items = await this.consolidate(detections); // 6. Guardar resultados await this.saveResults(sessionId, items); // 7. Calcular COGS await this.calculateCOGS(sessionId, frames.length); // 8. Actualizar status await this.updateStatus(sessionId, 'DONE'); // 9. Notificar usuario await this.notify(sessionId); } catch (error) { await this.updateStatus(sessionId, 'FAILED'); throw error; // Bull reintentara } } } ``` ### Configuracion de Cola ```typescript // queue.module.ts BullModule.registerQueue({ name: 'inventory', defaultJobOptions: { attempts: 3, backoff: { type: 'exponential', delay: 5000, // 5s, 10s, 20s }, removeOnComplete: 100, removeOnFail: 50, }, }); ``` --- ## Metricas | Metrica | Objetivo | |---------|----------| | Tiempo promedio | < 2 min | | Tasa de exito | > 95% | | Jobs en cola | < 100 | | Latencia cola | < 30s | --- ## Referencias - [Bull Documentation](https://docs.bullmq.io/) - [MII-005](../01-epicas/MII-005-procesamiento-ia.md) - Procesamiento IA - [INT-006](../02-integraciones/INT-006-ia-provider.md) - Integracion IA --- **Ultima Actualizacion:** 2026-01-10