Skip to content

Delay (Scheduled pause)

The Delay node halts a workflow for a configured amount of time (seconds, minutes, hours, or days) and resumes execution automatically when the deadline is reached, continuing from the next configured node. Unlike a blocking sleep, the Delay frees the server process during the wait: the state is persisted to the database and the workflow resumes in a new process when the scheduled time arrives.

The execution trace is continuous: nodes run before and after the delay appear in the same instance history.

FieldTypeRequiredDescription
delayAmountNumberYesHow long to wait
delayUnitSelectYesUnit: seconds, minutes, hours, days
nextModuleModuleYesNode that will execute when the delay expires
  1. The node calculates the exact resume date/time (now + delayAmount × delayUnit).
  2. Persists the continuation state in the workflow_delays table with status = waiting.
  3. Schedules a node-schedule job for that date.
  4. Returns _stopflowprocess: true to the engine, which pauses the flow and releases the execution slot.
  5. When the job fires, continueWorkflowAfterDelay calls the engine with the same instance workflow_id and the next node as the entry point.
  6. The engine detects the instance already exists, loads the steps recorded before the delay from the DB, and pre-populates the trace array — ensuring full session continuity.

If the server restarts while delays are pending, DelayMonitorService restores them automatically on startup: it reschedules jobs whose execution date has not yet passed and immediately executes any that expired during 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)
);

When the Delay node activates, it immediately returns this object to the engine (the flow stops here):

{
"nextModule": null,
"_stopflowprocess": true,
"_meta_": {
"delayScheduled": true,
"executeAt": "2025-06-10T14:30:00.000Z",
"jobName": "delay_wf_abc123_nodeId"
},
"data": {
"...": "flow data",
"delayInfo": {
"scheduledAt": "2025-06-10T14:30:00.000Z",
"delayAmount": 30,
"delayUnit": "minutes",
"status": "scheduled"
}
}
}
CodeDescription
MISSING_TABLEThe workflow_delays table does not exist in the database
INVALID_TABLE_STRUCTUREThe table exists but is missing required columns
INVALID_DELAY_AMOUNTdelayAmount is not a positive number
INVALID_DELAY_UNITdelayUnit is not one of the allowed values
MISSING_NEXT_MODULENo next node was configured
INVALID_EXECUTION_TIMEThe calculated date is already in the past
SCHEDULE_ERRORInternal error scheduling the job
{
"delayAmount": 5,
"delayUnit": "minutes"
}

Wait 1 day before sending a follow-up email

Section titled “Wait 1 day before sending a follow-up email”
{
"delayAmount": 1,
"delayUnit": "days"
}

Separate two processing batches by 30 seconds

Section titled “Separate two processing batches by 30 seconds”
{
"delayAmount": 30,
"delayUnit": "seconds"
}
  • The workflow does not hold an execution slot during the pause; other workflows run normally.
  • If the same workflow_id + delay_node_id pair already has a registered delay, INSERT ... ON DUPLICATE KEY UPDATE replaces the previous record (the prior job is cancelled and a new one is created).
  • The data flowing through the pipeline is serialized as JSON in continuation_data and restored on resume.
  • The full trace (nodes before and after the delay) is visible in the instance history.
  • SubWorkflow — executes a child flow synchronously while maintaining session linkage
  • Iterator — splits an array into batches and processes them sequentially or in parallel