Skip to main content

Configuration

Every setting lives in config/saga-lara-flow.php. This page walks through the sections you are most likely to touch.

Database​

'database' => [
'connection' => env('SAGA_LARA_FLOW_DB_CONNECTION'), // null = app default
'table_prefix' => env('SAGA_LARA_FLOW_TABLE_PREFIX', 'saga_'),
],

Point the engine at a dedicated connection to keep its tables separate from your domain data. The prefix is applied to every table, and to every index name derived from one, so it is capped at 24 bytes — 24 characters of ASCII, fewer if you use anything else. MySQL refuses an identifier past 64 characters and PostgreSQL truncates one past 63 bytes, and the longest name the schema asks for is 40. A longer prefix fails part-way through the initial migration; drop the package tables it did create before running migrate again, or the retry stops on the first table that already exists. The package tables always use this connection (via UsesSagaFlowConnection), so they are unaffected by tenant DB switching unless you leave the connection null.

Models​

'models' => [
'flow_run' => Models\FlowRun::class,
'action_run' => Models\ActionRun::class,
// flow_event, flow_signal, flow_tag, flow_child, compensation_run, side_effect …
],

Swap any model for your own subclass to extend behaviour (casts, relations, scopes).

FlowRun's relations read in the order their rows are meaningful in: actions(), compensations(), sideEffects() and children() by sequence, events() by recorded_at then id, and signals() and tags() by id. An order you append lands after that one — call reorder() first to read against it, and also before chunkById(), lazyById() or eachById(), whose cursor the default order would otherwise outrank.

Queue​

'queue' => [
'connection' => env('SAGA_LARA_FLOW_QUEUE_CONNECTION'),
'queue' => env('SAGA_LARA_FLOW_QUEUE', 'default'),
'after_commit' => env('SAGA_LARA_FLOW_AFTER_COMMIT', true),
'dispatch_mode' => DispatchMode::Queue,
],

Controls where a run's jobs go — workflow, action and compensation jobs alike; a child closed by its parent's close policy is rolled back inside the closing job, on the parent's. after_commit dispatches jobs only after the surrounding database transaction commits. Individual runs can override the connection/queue via ->onConnection() / ->onQueue() or the #[FlowQueue] attribute. A child run resolves each field from its class's #[FlowQueue], else from its parent, else from here — see child workflows.

Locks​

'locks' => [
'enabled' => true,
'workflow_ttl_seconds' => 900,
'action_ttl_seconds' => 900,
'compensation_ttl_seconds' => 900,
'block_seconds' => 5,
'prefix' => 'saga-lara-flow',
],

These configure the WithoutOverlapping middleware that keeps two jobs of one class off the same run or step at once — the idempotency guard. See Queues, locks & idempotency.

Monitor & repair​

monitor.expiration.defaults set implicit deadlines (seconds) for run / action / signal — null means no default. repair.* configures the doctor pass that recovers runs whose progress was lost to a dropped job. Both are covered in Expiration & monitoring.

Reclaim​

actions.reclaim.stale_running and sagas.reclaim.stale_running — off by default — let a Running row be claimed again once it has sat long enough since started_at to suspect its worker died. Not the same thing as a lock TTL. With it off, a worker killed mid-step leaves that step stuck. Reclaim & recovery covers the mechanism, how it differs from the other timing dials, and the full config and per-step override surface.

Logging​

'logging' => [
'anomaly_level' => env('SAGA_LARA_FLOW_ANOMALY_LOG_LEVEL', 'info'), // null = off
'channel' => env('SAGA_LARA_FLOW_LOG_CHANNEL'), // null = app default
],

The engine's second journal, for the things it absorbs silently: a claim lost to whoever already owned the row, an outcome write rejected because the row changed hands, and a batch already closed by a duplicate delivery. None of them fails a job, so these lines are the only trace. See Reclaim & recovery.

Policies​

'children' => ['default_close_policy' => ChildClosePolicy::Abandon],
'parallel' => ['default_failure_policy' => ParallelFailurePolicy::FailFast],
'sagas' => [
'default_compensation_failure_policy' => CompensationFailurePolicy::Stop,
'parallel_compensation' => false,
'compensate_failed_step' => false,
],

Defaults for child close behaviour, parallel-block failure handling, and saga compensation. Each can be overridden per builder call or per attribute — precedence is action/builder > group > config.

Tenancy​

'tenancy' => [
'auto' => false,
'capture' => null, // (): array
'restore' => null, // (array $context): void
'end' => null, // (?array $previous): void
],

Hooks for Octane / multi-tenant safety, each an invokable class name or a [Class::class, 'method'] pair resolved from the container — see Octane & multi-tenancy. A closure also works, but php artisan config:cache refuses a config that holds one.