Skip to content

Sistema de Background Jobs - Documentación Completa

Sistema: Background Jobs (Tareas en Segundo Plano) Estado: Implementado (Fases 1-3 completas) Fecha: 2026-02-05 Ultima actualizacion: 2026-02-26

Estado Actual: SSE Temporalmente Deshabilitado

⚠️ SSE deshabilitado temporalmente

El endpoint GET /backend/jobs/{id}/stream existe en el backend pero el frontend usa exclusivamente HTTP polling (useBackgroundJob) hasta que se refactorice el sistema de autenticación.

Causa técnica: El ACCESS_TOKEN se asigna en el dominio app.com mediante Request::syncCookies(). EventSource no puede enviar headers custom (Authorization) y el browser no envía cookies de app.com a api.com (cross-domain). La solución requiere unificar la estrategia de cookies o implementar un proxy SSE.

El hook useJobStream es actualmente un wrapper sobre polling HTTP. La interfaz SSE está diseñada para activarse cuando se resuelva el auth cross-domain.


Descripción

Sistema genérico para ejecutar operaciones de larga duración de forma asíncrona, liberando al usuario de esperar en el navegador. Implementa ejecución en background con notificaciones, consulta de estado y monitoreo.

Casos de uso:

  • Facturación masiva (500+ facturas, 3-10 minutos)
  • Reportes consolidados multi-schema (2-5 minutos)
  • Importación de datos CSV/Excel (5-15 minutos)
  • Sincronización AFIP (2-8 minutos)

Estructura de Documentación

📐 Arquitectura y Decisiones

architecture.md (649 líneas)

  • Problema arquitectural
  • Solución seleccionada: SSE + PostgreSQL NOTIFY
  • Roadmap de implementación (4 fases)
  • Escalabilidad y migración a RabbitMQ
  • Patrones utilizados

frontend-notification-dispatch-process.md

  • Cadena de despacho de notificaciones de jobs en el frontend (Tier 1 → 2 → 2.5 → 3)
  • Recuperacion de resultado via URL-param (action_url, ?job_id=)
  • Generacion de action_url en backend, invariantes, extensibilidad

adrs/ (7 ADRs)

  • ADR-001: Ejecución con exec() + CLI Worker
  • ADR-002: Tablas por Schema Multi-Tenant
  • ADR-003: Polling → SSE Progresivo
  • ADR-004: Wrapper Pattern (NO Refactoring)
  • ADR-005: Schema Isolation en Background (CRÍTICO)
  • ADR-006: CLI Two-Phase Bootstrap
  • ADR-007: Tab-Scoped Job Bus via window.BautistaJobBus

🔧 Implementación Técnica

backend/ (9 archivos, 3,325 líneas)

  • Arquitectura de componentes (Value Objects, Services, Handlers, Controllers)
  • Base de datos (tablas, índices, constraints)
  • API endpoints (POST /jobs, GET /jobs/{id}, SSE)
  • Handlers (implementación de nuevos jobs)
  • Multi-tenant (CRÍTICO) - Schema isolation
  • Testing (Unit + Integration)
  • Troubleshooting
  • Referencia de código

Tecnologías

Stack:

  • PHP 8.2+ con exec() para lanzar workers CLI
  • PostgreSQL (storage + NOTIFY para real-time)
  • Server-Sent Events (SSE) para notificaciones
  • React/TypeScript frontend

Dependencias: CERO externas (solo PHP + PostgreSQL)


Fases de Implementacion

Fase 1: MVP con Polling — COMPLETADA

  • Ejecucion asincrona con exec() + CLI worker
  • Tabla background_jobs + background_notifications
  • HTTP polling cada 2 segundos via useBackgroundJob (TanStack Query)
  • JobHandlerRegistry con auto-descubrimiento via PHP-DI (array job.handlers)
  • Todos los jobs llevan nro_sistema y prueba para aislamiento multi-tenant
  • Handlers implementados: BatchInvoicingJobHandler, entre otros

Fase 2: SSE Real-Time — BACKEND COMPLETO / FRONTEND PENDIENTE

  • PostgreSQL NOTIFY/LISTEN: trigger notify_job_update() implementado
  • JobStreamController: endpoint GET /backend/jobs/{id}/stream funcional en backend
  • Frontend SSE bloqueado: EventSource no puede enviar headers auth cross-domain (ver ADR-003 ENMIENDA)
  • Hook useJobStream retorna isConnected: false, usingSseFallback: true (constantes) y delega a polling
  • Para desbloquear: resolver cross-domain cookie strategy o proxy en app.com

Fase 3: Production Hardening — COMPLETADA

  • Retry con exponential backoff
  • Monitoring: GET /backend/jobs/health y GET /backend/jobs/metrics (formato Prometheus), protegidos con METRICS_SECRET
  • AdminJobController: endpoints /backend/jobs/admin/* para operaciones administrativas
  • Supervisor para gestion de workers (config en supervisor/bautista-worker.conf.dist)
  • Cleanup automatico de jobs antiguos

Fase 4: Escalar con RabbitMQ (Futuro)

  • Cuando volumen > 500 jobs/dia
  • Worker pool distribuido
  • Priority queues
  • Dead letter queue

TemaArchivo
¿Por qué esta solución?architecture.md
¿Cómo implementar?backend/README.md
¿Qué tareas se hicieron?Kanban archivado — implementación completada 2026-02-24
¿Qué decidimos?adrs/README.md
¿Cómo testear multi-tenant?backend/05-multi-tenant.md
¿Problemas comunes?backend/07-troubleshooting.md
¿Cómo funciona la campana y los Tiers?frontend-notification-dispatch-process.md

Métricas

Total documentación: 5,237 líneas

  • Arquitectura: 649 líneas
  • ADRs: 39.7 KB (5 decisiones)
  • Backend: 3,325 líneas (9 archivos)
  • Kanban: 37 tarjetas implementadas (archivado 2026-02-24)

Complejidad: Media Time to Market: 4-5 semanas Costo Infraestructura: $0/mes


Siguientes Pasos

  1. Documentacion completa -- COMPLETADO
  2. Revision y aprobacion de arquitectura -- COMPLETADO
  3. Fase 1: MVP con Polling -- COMPLETADO
  4. Fase 2: Backend SSE -- COMPLETADO
  5. Fase 3: Production Hardening -- COMPLETADO
  6. Pendiente: Desbloquear SSE en frontend (requiere resolver auth cross-domain)
  7. Futuro: Fase 4 (RabbitMQ) cuando volumen lo justifique

Ultima actualizacion: 2026-02-26