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
{
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
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:
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=errory los camposchannel,target,error. - En el endpoint
/test-alertslos errores sí 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 |