Saltar a contenido

Alertas (onJobFailed)

Cuando un job agota sus 5 reintentos y falla permanentemente, el sistema dispara las alertas configuradas en el flow. Soporta tres canales: email, webhook y Slack, con filtrado opcional por destino.

Diagrama

flowchart TD
    A[Job falla] --> B{¿attempts < 5?}
    B -->|Sí| C[Retry con backoff]
    C --> A
    B -->|No| D[Fallo permanente]
    D --> E[Leer flow.alerts.onJobFailed]
    E --> F{¿Hay canales?}
    F -->|No| Z[Fin]
    F -->|Sí| G[Filtrar por adapter destino]
    G --> H[Despachar canales en paralelo]
    H --> I1[📧 Email SMTP]
    H --> I2[🔗 Webhook HTTP]
    H --> I3[💬 Slack Block Kit]

Configuración Básica

Los canales se definen en el flow:

{
  name: 'clientes',
  source: { adapter: 'tango' },
  destinations: ['wms', 'mysql-web'],
  pollInterval: 5 * 60 * 1000,
  priority: 'normal',
  alerts: {
    onJobFailed: [
      { type: 'email', to: ['ops@empresa.com'] },
      { type: 'slack', webhookUrl: 'https://hooks.slack.com/services/X/Y/Z' },
    ],
  },
}

Sin alerts o con onJobFailed: [], no se notifica nada (solo queda el log de error).

Tipos de Canal

Email

{
  type: 'email',
  to: 'ops@empresa.com',                    // string o string[]
  subject: 'URGENTE: fallo en clientes',    // opcional
}
Campo Tipo Descripción
to string | string[] Destinatario(s). Múltiples direcciones se mandan en un solo email (CSV).
subject string? Asunto custom. Default: [ERP Sync] Job fallido: {flow} ({pk}).

Requiere SMTP configurado en variables de entorno (SMTP_HOST, SMTP_PORT, SMTP_USER, SMTP_PASS, SMTP_FROM, SMTP_SECURE).

El cuerpo HTML incluye: flow, adapter, acción, PK, intentos, timestamp, mensaje de error y JSON de los datos del job.

Webhook

{
  type: 'webhook',
  url: 'https://hooks.miservicio.com/erp-sync',
  method: 'POST',                                  // o 'PUT', default POST
  headers: { Authorization: 'Bearer TOKEN' },      // opcional
}

POST con body JSON:

{
  "event": "job.failed",
  "service": "erp-wms-sync",
  "flow": "clientes",
  "entity": "clientes",
  "adapter": "wms",
  "action": "upsert",
  "pk": "CLI001",
  "data": { /* row del job */ },
  "error": "HTTP 500: ...",
  "attempts": 5,
  "timestamp": "2026-05-08T12:34:56.789Z"
}

Timeout: 10s. Respuesta no-2xx se loguea pero no propaga error.

Slack

{
  type: 'slack',
  webhookUrl: 'https://hooks.slack.com/services/T0XXX/B0YYY/ZZZ',
}

Envía mensaje con Block Kit: header rojo + sección de metadata (flow, adapter, acción, PK, intentos, timestamp) + bloque con el mensaje de error.

Filtrado por Destino

Destinos múltiples → alertas selectivas

Cuando un flow escribe a varios destinations (ej: ['wms', 'mysql-web']), cada canal puede limitarse a fallos de un subconjunto con el campo opcional destinations.

Cómo funciona

Cada canal acepta un campo opcional destinations: string[] (lista blanca de adapters). El canal solo dispara cuando job.adapter está en la lista. Sin el campo (o lista vacía), el canal aplica a todos los destinos del flow — comportamiento por defecto, retrocompatible.

Ejemplo

{
  name: 'clientes',
  destinations: ['wms', 'mysql-web', 'mysql-development'],
  alerts: {
    onJobFailed: [
      // Solo cuando falla el sync al WMS → equipo de operaciones
      {
        type: 'email',
        to: ['ops@empresa.com'],
        destinations: ['wms'],
      },
      // Solo cuando falla alguno de los destinos MySQL → DBA
      {
        type: 'email',
        to: ['dba@empresa.com'],
        destinations: ['mysql-web', 'mysql-development'],
      },
      // Sin `destinations` → notifica cualquier fallo del flow
      { type: 'slack', webhookUrl: 'https://hooks.slack.com/services/X/Y/Z' },
    ],
  },
}
Job que falla ops@ recibe email dba@ recibe email Slack notifica
wms
mysql-web
mysql-development

Diagrama

flowchart LR
    JOB[Job falla en<br/>adapter=mysql-web] --> FILTER{Filtrar por<br/>destinations}
    CH1[Canal email<br/>destinations: wms] --> FILTER
    CH2[Canal email<br/>destinations: mysql-*] --> FILTER
    CH3[Canal slack<br/>sin destinations] --> FILTER
    FILTER -->|wms NO matchea| SKIP1[Skip]
    FILTER -->|mysql-web matchea| OK1[📧 dba@]
    FILTER -->|sin filtro| OK2[💬 Slack]

Test de Alertas

Endpoint dedicado para probar la configuración sin esperar a que falle un job:

curl -X POST http://localhost:8080/flow/clientes/test-alerts

Respuesta (200 si todos OK, 207 Multi-Status si alguno falla):

{
  "flow": "clientes",
  "results": [
    { "type": "email",   "target": "ops@empresa.com",  "ok": true },
    { "type": "email",   "target": "dba@empresa.com",  "ok": true },
    { "type": "slack",   "target": "https://...",      "ok": false,
      "error": "HTTP 404" }
  ]
}

El test no aplica el filtro destinations

El payload de prueba usa adapter: 'test' y el endpoint dispara todos los canales sin filtrar — esto permite verificar la conectividad de cada canal aunque tenga destinations: ['wms']. El filtro solo se aplica en producción cuando llega un job real con su adapter concreto.

Manejo de Errores

  • Los errores en el envío de alertas se absorben silenciosamente en producción (no rompen el flujo del worker).
  • Quedan logueados con level=error y los campos channel, target, error.
  • En el endpoint /test-alerts los errores se exponen para que se pueda diagnosticar.

Convenciones

Caso Recomendación
Equipo único responsable Un solo canal email/slack sin destinations
Destinos críticos vs. secundarios Email al equipo de cada destino + Slack global
Webhooks de monitoreo (PagerDuty, n8n) Sin destinations, agregan contexto en el body
Alerta crítica en horario no laboral subject custom con URGENTE para reglas de filtrado en el cliente de email