miinventario-v2/docs/97-adr/ADR-0002-procesamiento-asincrono.md
rckrdmrd 1a53b5c4d3 [MIINVENTARIO] feat: Initial commit - Sistema de inventario con análisis de video IA
- Backend NestJS con módulos de autenticación, inventario, créditos
- Frontend React con dashboard y componentes UI
- Base de datos PostgreSQL con migraciones
- Tests E2E configurados
- Configuración de Docker y deployment

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-13 02:25:48 -06:00

225 lines
6.0 KiB
Markdown

# 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<ProcessVideoData>) {
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