Ir al contenido

Planificador de Workflows

El Planificador de Workflows es una vista de gestion que muestra cuando se ejecutan tus workflows programados, cuanto duran realmente, y donde compiten por los mismos servicios externos. Esta pensado para responder a preguntas operativas como:

  • Que esta corriendo el lunes a las 8 de la manana?
  • Hay dos workflows tocando el mismo SMTP a la vez?
  • Donde tengo huecos libres para programar un nuevo proceso pesado?
  • Que tan saturado esta cada dia de la semana?

A diferencia de la vista de Workflows (que es operativa, “ejecutar/editar”), el Planificador es estrategica: te ayuda a organizar el tiempo de ejecución del sistema completo.

Desde el menú lateral: Planificador.

La ruta es /workflow-planner. Aparece automáticamente para cualquier usuario autenticado del cliente.

El planificador combina dos fuentes de información reales del sistema:

  1. Workflows con cron activo del cliente actual (workflows.workflow_json.schedule con active_schedule = true).
  2. Historial de ejecuciones de la tabla workflowstates, agregado por nodo en una ventana configurable (7, 14, 30, 60 o 90 dias) — esto se usa para calcular la duración promedio de cada nodo y dibujar los segmentos proporcionalmente.

No usa datos de prueba. Si tu cliente no tiene workflows con cron activo, el planificador mostrará un estado vacío explicito. Los workflows manuales y los disparados por webhook no aparecen en esta versión (esta planeado para una segunda fase como “análisis de puntos calientes desde historial”).

Es un mapa de calor por dia: cada dia es una celda que muestra cuantas horas de ejecución total estan planificadas. Cuanto mas oscura, mas carga.

  • Modo Semana muestra los 7 dias (Lunes a Domingo).
  • Modo Mes muestra 30 dias (útil para detectar patrones mensuales).
  • Iconos rojos de aviso marcan los dias con colisiones de servicio detectadas.
  • Sirve para tener una vision rápida de la distribución semanal y detectar dias sobrecargados o vacios.

Es un diagrama tipo Gantt del dia seleccionado, con:

  • Columna fija a la izquierda con el nombre del workflow + horario + botón de menú de acciones.
  • Eje horario de 00h a 23h (con scroll horizontal si la pantalla es estrecha; la columna izquierda queda fija).
  • Una fila por workflow, con un bloque coloreado que representa su ejecución.
  • Segmentos por nodo dentro del bloque, dimensionados proporcionalmente a la duración promedio de cada nodo en el historial. Los colores son estables por tipo de modulo (siempre el mismo color para mail_send, etc.).
  • Fila “Huecos libres” con franjas verdes que marcan periodos sin ningun workflow.
  • Bloques con borde rojo indican que ese workflow tiene una colision detectada con otro.

La mayoria de los workflows reales duran segundos. Si dibujaramos su duración exacta en una escala de 24h, los bloques serian invisibles (1 pixel). Por eso el planificador aplica un mínimo visible de 1 hora a cada bloque. Esto:

  • Garantiza que veas los segmentos por nodo.
  • Hace detectables las colisiones cercanas en tiempo (ej. dos cron a las 08:00 y 08:30).
  • No afecta al historial real ni a la duración promedio: solo cambia la representación grafica.

Esta es la parte mas importante de entender. No consideramos colision el simple hecho de que dos workflows se solapen en el tiempo. La definición exacta es:

Hay colision cuando dos workflows distintos ejecutan un nodo del mismo moduleName (mismo tipo de servicio) en horarios solapados.

Un workflow es solo un orquestador. Quien realmente compite por recursos son sus nodos, y especificamente el servicio externo que cada nodo invoca:

  • Si dos workflows corren a la vez pero uno habla con mail_send y el otro con dataStore, no se molestan: usan recursos distintos.
  • Si los dos hacen mail_send exactamente al mismo segundo, si se molestan: ambos pelean por el mismo proveedor SMTP, pueden chocar con rate limits, ordenar mal los correos, etc.

“Colision por servicio” te dice que problema operativo real vas a tener, no solo que dos crons se cruzan.

Para cada bloque del dia (workflow x ocurrencia):

  1. Se descompone el bloque en sub-intervalos por nodo, proporcionales a la duración promedio de cada nodo.

    Ejemplo: Sync CRM (08:00-09:00, total 60min visibles, 3 nodos):

    Nodo%Intervalo
    webhook8%08:00-08:04
    transformation60%08:04-08:48
    mail_send32%08:48-09:00
  2. Se comparan TODOS los pares de sub-intervalos entre bloques distintos del mismo dia. Para cada par (intervaloA, intervaloB):

    • Mismo dia?
    • Workflows distintos?
    • Mismo moduleName (tipo raiz)?
    • Sus tiempos se solapan? (max(startA, startB) < min(endA, endB))

    Las cuatro condiciones deben cumplirse para que cuente como colision.

  3. Si todas se cumplen, se registra la colision con el horario exacto del solape.

Setup:

  • Sync CRM, cron 0 8 * * 1 (Lunes 08:00). Nodos: webhook -> transformation -> mail_send.
  • Backup DB, cron 30 8 * * 1 (Lunes 08:30). Nodos: dataStore -> mail_send.

Análisis:

Ambos workflows tocan mail_send cerca del final de su ejecución. Con el mínimo visible de 1h:

  • Sync CRM ocupa 08:00-09:00; mail_send cae aproximadamente en 08:48-09:00.
  • Backup DB ocupa 08:30-09:30; mail_send cae aproximadamente en 09:18-09:30.

Si las proporciones se solapan en el tiempo, la tabla de colisiones mostrará una entrada del tipo:

DiaHorarioServicioWorkflow AWorkflow B
Lunes08:48-09:00mail_sendSync CRMBackup DB

Que hacer: cambiar el cron de Backup DB a 09:00 o configurar una credencial SMTP distinta para cada flujo.

Setup:

  • Invoice Cron, cron 0 6 * * 1 (Lunes 06:00). Nodos: billing -> pdf_generator -> mail_send.
  • Stock Update, cron 15 6 * * 1 (Lunes 06:15). Nodos: webhook -> transformation -> dataStore.

Análisis:

Visualmente los bloques se solapan en la franja 06:15-07:00. Pero los conjuntos de servicios son disjuntos: {billing, pdf_generator, mail_send} ∩ {webhook, transformation, dataStore} = vacío.

El algoritmo (correctamente) no cuenta esto como colision. La tabla de “Colisiones de servicio detectadas” mostrará 0 entradas relacionadas con este par.

Conclusion: el solape visual no implica conflicto operativo. Aunque el planificador los pinte uno encima del otro, ambos pueden correr en paralelo sin pelearse por recursos.

Caso 3 — Tres workflows, una colision encadenada

Sección titulada «Caso 3 — Tres workflows, una colision encadenada»

Setup:

  • Email Reports A, cron 0 14 * * 5. Nodos: dataframe -> mail_send.
  • Email Reports B, cron 5 14 * * 5. Nodos: dataframe -> mail_send.
  • Email Reports C, cron 10 14 * * 5. Nodos: dataframe -> mail_send.

Análisis:

Los tres se ejecutan en una ventana de 15 minutos. Con el mínimo visible de 1h, sus bloques son 14:00-15:00, 14:05-15:05 y 14:10-15:10. Todos terminan con mail_send.

La tabla mostrará tres colisiones (un par por combinación):

DiaHorarioServicioWorkflow AWorkflow B
Viernes14:48-15:00mail_sendReports AReports B
Viernes14:53-15:00mail_sendReports AReports C
Viernes14:53-15:05mail_sendReports BReports C

Que hacer: agruparlos en un único workflow paralelizable o espaciar los crons al menos por la duración total estimada.

Setup: workflow recien creado con cron activo pero sin ejecuciones registradas en workflowstates dentro de la ventana.

Análisis:

El backend devuelve el workflow con nodes: [] y totalDurationMs: 0. El planificador lo dibuja como un bloque del mínimo visible (1h) con un único segmento gris etiquetado “(sin historial)”.

No genera colisiones porque su moduleName ficticio nunca coincidira con un servicio real.

Que hacer: ejecutar el workflow al menos una vez (manualmente o esperando al cron) para que aparezcan duraciones reales en la siguiente carga del planificador.

Cada fila tiene un menú contextual (icono de tres puntos en la columna izquierda) con seis opciones:

OpciónQue hace
Ver resumenNavega al resumen del workflow (/workflows/summary/:id)
Ir al EditorAbre el editor visual del workflow
EjecutarLanza el workflow manualmente (no afecta la planificación)
ProgramarAbre un dialog para editar el cron y activar/desactivar la programación
Ver incidenciasMuestra un dialog con incidencias abiertas y resueltas
Ver comentariosAbre la caja de comentarios del workflow

El dialog usa el componente CronExpressionField (el mismo del editor de workflows). Al guardar:

  1. Llama a PUT /api/workflows/:id/schedule para actualizar el cron y el flag active_schedule.
  2. Recarga automáticamente la planificación completa.
  3. Recalcula bloques, ocurrencias y colisiones — porque cambiar un cron puede crear o resolver una colision en otro dia/hora.

Esto hace del planificador una herramienta interactiva: puedes mover horarios y ver el efecto al instante en el grafico.

El botón Exportar Reporte genera un PDF horizontal A4 con:

  1. Encabezado: título, fecha de generación y vista actual (Macro/Detalle).
  2. Captura limpia del grafico actual (renderizada con html2canvas, escala 2x para nitidez).
  3. Tabla de colisiones detectadas redibujada con jsPDF (texto seleccionable, no imagen) con columnas: Dia, Horario, Servicio, Workflow A, Workflow B. Página automáticamente si hay muchas filas.

El reporte es útil para revisiones internas, auditorias de planificación o para documentar cambios de cron antes/después.

El selector “Historial” (arriba a la derecha) controla cuantos dias hacia atras se promedia para calcular las duraciones por nodo:

VentanaCuando usarla
7 diasDiagnostico de un problema reciente
14 diasVista de tendencia corta
30 diasDefault — recomendado para planificación habitual
60 diasWorkflows con poca frecuencia (semanales/quincenales)
90 diasWorkflows mensuales o vista de largo plazo

Cambiar la ventana provoca una recarga automática del endpoint.

GET /api/workflow/planner-schedules?days=30

Requiere autenticación (token Bearer). Devuelve:

{
"success": true,
"data": [
{
"workflowId": 102,
"workflowName": "Sync CRM",
"cron": "0 8 * * 1",
"isplay": 1,
"occurrences": [
{ "dayOfWeek": 0, "startHour": 8.0 }
],
"totalDurationMs": 4500,
"executions": 28,
"nodes": [
{
"nodeId": "1",
"nodeName": "webhook_1",
"moduleName": "webhook",
"avgDurationMs": 200,
"executions": 28,
"proportion": 0.044
}
]
}
],
"windowDays": 30
}

Notas:

  • dayOfWeek: 0 = Lunes, 6 = Domingo (formato ISO).
  • startHour: hora decimal (ej. 8.5 = 08:30).
  • nodeName es la instancia (ej. webhook_1); moduleName es el tipo raiz (ej. webhook) usado para detectar colisiones.
  • proportion: porcentaje del tiempo total del workflow ocupado por ese nodo (0..1).
  • isplay: estado del workflow en la BD (1 = corriendo, otros valores = pausado/borrador).

El endpoint omite workflows sin cron activo y workflows con isplay = 0 (eliminados).

  1. No detecta colisiones por credencial: dos mail_send con cuentas SMTP distintas todavia se cuentan como colision. Esta planeado para una fase 2 (requiere leer la configuración de cada nodo).
  2. No incluye workflows manuales ni webhooks: solo se muestran los que tienen cron activo. La fase 2 analizara el historial para mostrar “puntos calientes” de ejecuciones manuales/webhook.
  3. Mínimo visible de 1 hora: workflows muy rapidos (segundos) pueden parecer mas grandes de lo que son. Es una decision deliberada para que las colisiones sean visibles.
  4. El cron debe ser estándar: el endpoint usa cron-parser. Expresiones no soportadas (anios, segundos exactos, alias propios) se omiten silenciosamente.
  • Antes de programar un workflow nuevo: abre el planificador, busca un hueco libre verde en el dia y la franja horaria deseados, y configura el cron para que caiga ahi.
  • Después de un cambio de horario: re-abre el planificador y verifica que no hayas creado una colision al mover un workflow.
  • Auditoria semanal: exporta un PDF cada lunes y archivalo. Sirve para tener trazabilidad de la evolución de la planificación del cliente.
  • Diagnosticar fallos de envío: si tienes errores intermitentes en mail_send, busca en el planificador si hay varios workflows que disparan emails simultaneamente. La causa suele ser una colision por rate limit.
SintomaCausa probableSolución
No aparece ningun workflowEl cliente no tiene workflows con active_schedule = truePrograma al menos un workflow desde el editor o desde el menú Programar
Los bloques estan vacios “(sin historial)“El workflow nunca se ha ejecutado en la ventana de historialEjecutalo manualmente una vez o ampliar la ventana de historial
Veo solape visual pero 0 colisionesLos workflows usan servicios distintos (caso correcto)No hay acción necesaria — no es una colision real
El cron muestra una hora incorrectaEl campo schedule del JSON del workflow no se actualizoEdita el cron desde el menú Programar del planificador
El PDF sale con texto cortadoHay demasiadas colisiones para una páginajsPDF agrega páginas automáticamente, el contenido completo esta presente