Ir al contenido

Delay (Pausa programada)

El nodo Delay detiene la ejecución del workflow durante un período de tiempo configurado (segundos, minutos, horas o días) y la reanuda automáticamente al cumplirse el plazo, continuando desde el nodo siguiente. A diferencia de un sleep bloqueante, el Delay libera el proceso del servidor durante la pausa: el estado se persiste en base de datos y el workflow continúa en un nuevo proceso cuando llega la hora programada.

La traza de ejecución es continua: los nodos ejecutados antes y después del delay aparecen en el mismo historial de instancia.

CampoTipoRequeridoDescripción
delayAmountNúmeroSíCantidad de tiempo a esperar
delayUnitSelecciónSíUnidad: seconds, minutes, hours, days
nextModuleMóduloSíNodo que se ejecutará cuando expire el delay
  1. El nodo calcula la fecha y hora exacta de reanudación (now + delayAmount × delayUnit).
  2. Persiste el estado de continuación en la tabla workflow_delays con status = waiting.
  3. Programa un job en node-schedule para esa fecha.
  4. Retorna _stopflowprocess: true al motor, que pausa el flujo y libera el slot de ejecución.
  5. Cuando el job dispara, continueWorkflowAfterDelay llama al motor con el mismo workflow_id de instancia y el nodo siguiente como punto de entrada.
  6. El motor detecta que la instancia ya existe, carga los steps previos al delay desde la BD y los pre-popula en el array de traza, garantizando la continuidad del historial.

Si el servidor se reinicia mientras hay delays pendientes, el DelayMonitorService los restaura automáticamente al arrancar: re-programa los jobs cuya fecha de ejecución todavía no ha llegado y ejecuta inmediatamente los que vencieron durante el downtime.

CREATE TABLE workflow_delays (
id INT AUTO_INCREMENT PRIMARY KEY,
workflow_id VARCHAR(255) NOT NULL,
client_id INT NOT NULL,
next_module VARCHAR(255) NOT NULL,
continuation_data TEXT NOT NULL,
scheduled_at DATETIME NOT NULL,
delay_node_id VARCHAR(255) NOT NULL,
status ENUM('waiting', 'executed', 'error', 'cancelled') DEFAULT 'waiting',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
executed_at TIMESTAMP NULL,
error_message TEXT NULL,
UNIQUE KEY unique_workflow_delay (workflow_id, delay_node_id)
);

Cuando el nodo Delay se activa, devuelve inmediatamente este objeto al motor (el flujo se detiene aquí):

{
"nextModule": null,
"_stopflowprocess": true,
"_meta_": {
"delayScheduled": true,
"executeAt": "2025-06-10T14:30:00.000Z",
"jobName": "delay_wf_abc123_nodeId"
},
"data": {
"...": "datos del flujo",
"delayInfo": {
"scheduledAt": "2025-06-10T14:30:00.000Z",
"delayAmount": 30,
"delayUnit": "minutes",
"status": "scheduled"
}
}
}
CódigoDescripción
MISSING_TABLELa tabla workflow_delays no existe en la base de datos
INVALID_TABLE_STRUCTURELa tabla existe pero le faltan columnas requeridas
INVALID_DELAY_AMOUNTdelayAmount no es un número positivo
INVALID_DELAY_UNITdelayUnit no es uno de los valores permitidos
MISSING_NEXT_MODULENo se configuró el nodo siguiente
INVALID_EXECUTION_TIMELa fecha calculada ya es pasada
SCHEDULE_ERRORError interno al programar el job

Reintentar una llamada HTTP después de 5 minutos

Sección titulada «Reintentar una llamada HTTP después de 5 minutos»
{
"delayAmount": 5,
"delayUnit": "minutes"
}

Esperar 1 día antes de enviar un email de seguimiento

Sección titulada «Esperar 1 día antes de enviar un email de seguimiento»
{
"delayAmount": 1,
"delayUnit": "days"
}

Separar dos lotes de procesamiento por 30 segundos

Sección titulada «Separar dos lotes de procesamiento por 30 segundos»
{
"delayAmount": 30,
"delayUnit": "seconds"
}
  • El workflow no ocupa un slot de ejecución durante la pausa; otros workflows pueden ejecutarse con normalidad.
  • Si el mismo par workflow_id + delay_node_id ya tiene un delay registrado, el INSERT ... ON DUPLICATE KEY UPDATE reemplaza el registro anterior (el job previo se cancela y se crea uno nuevo).
  • Los datos que circulan por el flujo se serializan como JSON en continuation_data y se restauran al reanudar.
  • La traza completa (nodos antes y después del delay) es visible en el historial de la instancia.
  • SubWorkflow — ejecuta un flujo hijo de forma síncrona manteniendo la sesión
  • Iterator — divide un array en lotes y los procesa secuencialmente o en paralelo