Workflows & definitions
A workflow definition is a plain data structure. The same shape is what you
build in code, what php artisan workflow:build writes, and what is stored in
the workflows table.
[
'id' => 'send-welcome-email', // stable, chosen by you
'name' => 'Send Welcome Email',
'trigger' => ['type' => '@wf::trigger.manual', 'config' => []],
'nodes' => [
['id' => 'greet', 'type' => '@wf::action.log', 'config' => ['message' => 'Hi {{ trigger.name }}']],
],
'edges' => [
['from' => 'trigger', 'to' => 'greet', 'branch' => 'main'],
],
'meta' => [],
]
The pieces
trigger
{ type, config }. The type is a trigger identifier (see Triggers);
config is the trigger's saved settings. When an execution starts, the engine
fires the trigger against the incoming payload — the trigger decides whether an
execution should run at all.
nodes
An ordered list of { id, type, config }. The id is yours and must be unique
within the workflow; it's how edges refer to the node and how expressions read
its output ({{ nodes.<id>.* }}). type selects the node class. config is the
node's settings, and its string values may contain {{ }} expressions that are
resolved just before the node runs.
A node's config may also carry connection and __advanced__ keys — see
advanced settings below.
edges
An ordered list of { from, to, branch }. from and to are node ids (or the
literal 'trigger' for the entry edge). branch names which of the source
node's outgoing branches this edge belongs to.
Most nodes have a single main branch. Branching nodes declare more:
| Node | Branches |
|---|---|
| Condition | true, false |
| Switch | default, plus one branch per configured case |
| Loop | body (once per item), main (after the last item) |
| Scope | body (the grouped run), then continues on main |
Working with definitions in code
A definition is stored as a Workflow Eloquent model — create, update, and
query it like any other model:
use Qanna\WorkflowEngine\Models\Workflow;
$workflow = Workflow::create($data);
$workflow->nodes = [...$workflow->nodes, $newNode];
$workflow->save();
Workflow::find('send-welcome-email'); // ?Workflow
Workflow::active()->get(); // active only
See Storage for the other models.
Versioning
The Workflow model is an editable draft. Publishing it snapshots the draft
as the next numbered version, and only the published version runs — so you
can edit a workflow without affecting runs until you publish. See
Publishing & versions.
When an execution starts, the engine also captures a snapshot of the definition it runs into the execution record — so later publishes never rewrite what a past run actually executed, and a suspended execution resumes against the definition it started with.
Node types can also be versioned independently with a {vN} suffix so a node's
schema can change without breaking saved workflows. See
Node versioning.
Advanced settings
Every node can declare extra field groups beyond its main config:
connection— connection-style settings (Node::connection()).advanced— settings that matter but would clutter the main form (Node::advanced()).
The engine reads a handful of advanced keys itself, on every node, to govern
retries and timeouts:
| Key | Default | Effect |
|---|---|---|
max_retries | 0 | If the node's handle() throws, it is attempted again, up to max_retries total attempts (minimum one). A value of 1 behaves the same as 0. |
retry_delay | 1 | Seconds to sleep() between attempts. |
retry_backoff | fixed | fixed keeps retry_delay constant; exponential uses retry_delay * 2^(n-1). |
timeout | 0 | Seconds. When a node runs longer, a workflow.node-slow hook fires and a warning log row is written. On the CLI (and where pcntl is available) a hard alarm is also armed. |
A retried node emits a workflow.node-retrying hook and a retrying log row for
each extra attempt. If every attempt throws, the node's result is an error and
the workflow fails with the last exception message.
In a stored definition these live under the node's config as __advanced__ /
connection. The interactive builder prompts for them as separate "Advanced
settings" / "Connection settings" steps when a node declares them.