Appearance
Flow Execution
Overview
This document describes the current architecture and lifecycle of flow execution in the FlowBuilder system, reflecting the latest modular and decoupled design.
Execution Lifecycle
The execution of a flow follows these main steps:
- Trigger: A trigger initiates the flow execution.
- Validation: The flow is validated to ensure it meets minimum requirements.
- Process Creation: A
FlowProcess
object is created to control execution. - Job Dispatch: The
ProcessFlowJob
is dispatched to handle the execution asynchronously. - Node Execution: Each node is executed in sequence, with state and variables managed independently.
- Completion or Failure: The process is marked as completed or failed, and all results and logs are recorded.
Key Classes and Responsibilities
- ProcessFlowJob: Orchestrates the flow execution, delegating responsibilities to specialized classes.
- FlowProcessService (
App\FlowProcessing
): Handles process state transitions, node navigation, and process completion. - NodeExecutionService (
App\FlowProcessing
): Executes nodes, manages output variables, and logs execution results. - FlowProcessExceptionHandler (
App\FlowProcessing
): Centralizes error handling and logging for the flow process. - FlowProcess: Represents the execution instance, storing state, variables, and logs.
- NodeExecutionResponse: Encapsulates the result of a node execution, including status, output, and optional
redirectNodeId
for node redirection.
Execution Flow
1. Triggering the Flow
A trigger (manual, scheduled, webhook, etc.) fires the FlowTriggeredEvent
.
php
// Example: Manually triggering a flow
$flow = Flow::find(1);
$triggerNode = $flow->findNode(ManualTrigger::class)->toBaseNode();
$triggerNode->trigger();
2. Event Handling and Job Dispatch
The event is handled and a ProcessFlowJob
is dispatched with the event data:
php
event(new FlowTriggeredEvent($flow, $triggerNode));
// ...
ProcessFlowJob::dispatch($event);
3. Job Orchestration
The ProcessFlowJob
:
- Initializes the process and variables.
- Instantiates the services (
FlowProcessService
,NodeExecutionService
,FlowProcessExceptionHandler
). - Delegates process state transitions, node execution, and error handling to these services.
- Controls recursion depth to prevent infinite loops.
4. Node Execution
Each node is executed via the NodeExecutionService
, which:
- Parses and injects variables.
- Calls the node's
execute()
method. - Logs the execution and updates output variables if needed.
- Returns a
NodeExecutionResponse
indicating the next action (continue, wait, complete, fail, or redirect to another node viaredirectNodeId
).
5. Process State Management
The FlowProcessService
manages:
- Advancing to the next node.
- Marking the process as running, waiting, completed, or failed.
- Navigating between nodes based on connections.
Example: Node Execution and Response Usage
A node should return a NodeExecutionResponse using the static factories. For example, an HTTP node might look like:
php
public function execute(): NodeExecutionResponse
{
$result = Http::withHeaders(json_decode($this->data['headers'] ?? '[]', true) ?? [])
->post($this->data['url'], $this->data['body'] ?? [])
->throw();
return NodeExecutionResponse::continue(
outputVariable: $result->json(),
);
}
A node can return a NodeExecutionResponse with a redirectNodeId
to force the flow to jump to a specific node. If the node does not exist, the flow is completed immediately.
php
return NodeExecutionResponse::continue(
outputVariable: $result,
redirectNodeId: 'target-node-id',
);
The NodeExecutionResponse supports the following static factories:
continue(mixed $outputVariable, ?string $redirectNodeId = null)
— Continue the flow, optionally passing an output variable and/or redirecting to a specific node.waitForUserAction(?string $message = null, mixed $outputVariable = null, ?\Closure $onWaitCallback = null)
— Pause the flow and wait for user action.completeFlow(?string $message = null, mixed $outputVariable = null, ?\Closure $onCompleteCallback = null)
— Mark the flow as completed.failed(string $message)
— Mark the flow as failed with a message.
You can check the response status using methods like:
$response->shouldContinueFlow()
$response->shouldWaitForUserAction()
$response->shouldCompleteFlow()
$response->hasFailed()
And access output variables or messages:
$response->getOutputVariable()
$response->getMessage()
Monitoring and Debugging
- All node executions are logged in the
FlowProcess
. - You can query processes, inspect logs, and analyze failures using the
FlowProcess
model. - The modular design allows for easy extension and testing of each part of the execution pipeline.
For more details, see the source code in app/FlowProcessing
and the ProcessFlowJob
implementation.