Skip to content

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:

  1. Trigger: A trigger initiates the flow execution.
  2. Validation: The flow is validated to ensure it meets minimum requirements.
  3. Process Creation: A FlowProcess object is created to control execution.
  4. Job Dispatch: The ProcessFlowJob is dispatched to handle the execution asynchronously.
  5. Node Execution: Each node is executed in sequence, with state and variables managed independently.
  6. 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 via redirectNodeId).

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.