Job & action model
How EzFlow models jobs, actions, retries, and failure handling.
Every Workflow execution is modelled as a Job containing one Action per node that ran. This page documents the fields on each record and explains the outbox pattern EzFlow uses to keep execution state durable.
See Executions & Jobs for a higher-level explanation of how a run progresses.
Job
A Job is created when a Workflow trigger fires (or a test run begins) and tracks the full execution.
| Field | Type | What it is |
|---|---|---|
id | string | Unique identifier (CUID) |
status | string | Current state of the run (e.g. COMPLETED, WAITING) |
startedAt | datetime | When execution began |
finishedAt | datetime? | When execution ended — null if the Job is still running or WAITING |
duration | float? | Total wall-clock time in milliseconds |
workflowId | string | The Workflow that owns this run |
firedTriggerId | string? | The FiredTrigger record that initiated this run, if trigger-driven |
tenantId | string | The workspace that owns this Job |
originIp | string? | IP address of the request that started the run (HTTP triggers only) |
Action
An Action is created for each node that executes within a Job.
| Field | Type | What it is |
|---|---|---|
id | string | Unique identifier (CUID) |
moduleType | string | The node type that ran (e.g. SEND_WHATSAPP, LLM_COMPLETION, CONDITIONAL) |
moduleId | string | The node's ID within the Workflow DAG |
status | string | Whether the node succeeded or failed |
payload | string | Serialised input data the node received |
output | JSON? | The data the node produced for downstream nodes |
startedAt | datetime | When this node began executing |
finishedAt | datetime? | When this node finished |
duration | float? | Time the node took, in milliseconds |
jobId | string? | The parent Job |
The outbox pattern
EzFlow uses an outbox pattern to guarantee that Job and Action records are written durably even if a failure occurs mid-execution.
JobOutbox
Buffers a new Job record before it is committed to the main jobs table. The status field cycles through:
| Value | Meaning |
|---|---|
WAITING | The Job has been queued but not yet committed |
READY | Ready for the consumer to pick up and write |
SENT | The record has been written to the main table |
REMOVE | Marked for cleanup |
The version field enables optimistic concurrency so concurrent consumers do not double-write the same Job.
ActionOutbox
Mirrors the Action record structure and similarly buffers per-node results before they are committed. It includes a tenantId field for tenant-scoped writes, ensuring every node's output is persisted even if a subsequent node fails.
Failure tracking
When a node fails, EzFlow records a FailedItem linked to the Job. Key fields:
| Field | What it is |
|---|---|
trackingId | Correlation ID propagated through the run |
errorType / errorMessage | The failure details |
nodeType | The moduleType of the node that failed |
maxAttempts | Maximum number of retry attempts configured for this node |
retryAttempt | How many retries have been attempted so far |
nextRetryAt | When the next retry is scheduled |
Each retry attempt is logged in a RetryAttempt record with its scheduled time, execution time, status, delay, and any error message.
Related
- Run history — browse and inspect Jobs in the UI
- Wait & resume — how WAITING Jobs snapshot and resume
- Executions & Jobs — conceptual overview of how a run progresses