Skip to main content

Synchronous execution

runSync() drives the entire workflow in-process, using the same single replay loop as the queued path. It is handy for tests, tinkering, and short workflows that don't need to suspend:

$run = SagaFlow::create(CheckoutWorkflow::class)
->withArguments('order-42')
->runSync();

$run->status; // FlowStatus::Completed
$run->result; // the value handle() returned

The queued and synchronous paths are guaranteed to reach the same final database state — the only difference is who drives the steps (your worker vs. the current process).

A runSync() reached while another run is being driven — an action whose body starts a saga of its own — is driven on replay state of its own, so the run that owns the step keeps its ordinals and its compensation stack while the inner one runs. From inside handle(), reach another workflow through child() instead: runSync() there takes no ordinal and starts a run the next replay cannot recognize.

Do not call runSync() inside a transaction of your own

A step's body runs while your transaction is still open, so a rollback afterwards — yours, or one a failed statement forced on you — discards every row the run recorded while the work those rows describe is already done. A charge stays charged with nothing left to attribute it to, on every driver. The queued path is clear of this while saga-lara-flow.queue.after_commit is on, as it is by default: it holds the jobs until your transaction commits, and turning it off gives them the same problem. The same applies to signal(), cancel() and compensate() — see what a host transaction leaves behind.

When to use which​

run() (queued)runSync()
Returnsa Pending FlowRun immediatelya settled FlowRun
Drives stepson your queue workersin the calling process
Suspend/resumeyes (signals, queued actions)resolved inline where possible
Good forproduction, long-running flowstests, short flows, exploration
note

A workflow that awaits a signal cannot make progress under runSync() past the wait unless the signal was already delivered — synchronous execution has no worker to resume it later. Model long-running, human-in-the-loop flows with the queued path.