Konfigurácia
workflows:install publikuje config/workflows.php; samostatne ho publikujete takto:
php artisan vendor:publish --tag="workflows-config"Každý kľúč sa číta prísne: nesprávny typ vyhodí InvalidWorkflowsConfigurationException s názvom kľúča, hodnota mimo povoleného rozsahu ju vyhodí s názvom kľúča a rozsahom a prázdna hodnota (env KEY=) použije predvolenú. Každá chyba konfigurácie, vrátane chýb z čítačiek package-toolkit, je táto jedna trieda, takže stačí jeden catch. Trvania sú reťazce ISO 8601. Nastavenia tried musia uvádzať existujúcu triedu, ktorá implementuje príslušný kontrakt.
Konfiguračný súbor
<?php
declare(strict_types=1);
use RoundlyConsulting\Workflows\Http\Resources\WorkflowOwnerResource;
use RoundlyConsulting\Workflows\Http\Resources\WorkflowSubjectResource;
use RoundlyConsulting\Workflows\Http\Resources\WorkflowUserResource;
use RoundlyConsulting\Workflows\Models\StepRun;
use RoundlyConsulting\Workflows\Models\WorkflowDefinition;
use RoundlyConsulting\Workflows\Models\WorkflowDryRun;
use RoundlyConsulting\Workflows\Models\WorkflowEscalation;
use RoundlyConsulting\Workflows\Models\WorkflowIdempotencyKey;
use RoundlyConsulting\Workflows\Models\WorkflowInstance;
use RoundlyConsulting\Workflows\Models\WorkflowVersion;
use RoundlyConsulting\Workflows\Models\WorkflowWait;
use RoundlyConsulting\Workflows\Support\GateStepAuthorizer;
/*
| Every key is read through the package's strict readers: a typo throws naming the key, and a
| blank value (a host's `KEY=`) takes the default. Pass env values through raw.
*/
return [
/*
| Key types of the polymorphic columns: `bigint`, `uuid` or `ulid`. `key_type` governs the
| user morphs (started_by, published_by, requested_by); a blank `owner_key_type` or
| `subject_key_type` falls back to it. Every registered subject type must use the subject
| key type. `primary_key_type` is the type of the package's own ids.
*/
'key_type' => env('WORKFLOWS_KEY_TYPE', 'bigint'),
'owner_key_type' => env('WORKFLOWS_OWNER_KEY_TYPE'),
'subject_key_type' => env('WORKFLOWS_SUBJECT_KEY_TYPE'),
'primary_key_type' => env('WORKFLOWS_PRIMARY_KEY_TYPE', 'bigint'),
/*
| Swappable models: extend the packaged class and name the subclass here.
*/
'models' => [
'definition' => WorkflowDefinition::class,
'version' => WorkflowVersion::class,
'instance' => WorkflowInstance::class,
'step_run' => StepRun::class,
'wait' => WorkflowWait::class,
'escalation' => WorkflowEscalation::class,
'idempotency_key' => WorkflowIdempotencyKey::class,
'dry_run' => WorkflowDryRun::class,
],
'tables' => [
'definitions' => 'workflow_definitions',
'versions' => 'workflow_versions',
'instances' => 'workflow_instances',
'step_runs' => 'workflow_step_runs',
'waits' => 'workflow_waits',
'escalations' => 'workflow_escalations',
'idempotency_keys' => 'workflow_idempotency_keys',
'dry_runs' => 'workflow_dry_runs',
],
/*
| Every step runs as a queued job. With the queue off, the same steps run inline, one after
| another (an iterative runner, never nested dispatches). Blank connection / queue = the
| application defaults.
*/
'queue' => [
'enabled' => env('WORKFLOWS_QUEUE_ENABLED', true),
'connection' => env('WORKFLOWS_QUEUE_CONNECTION'),
'queue' => env('WORKFLOWS_QUEUE_NAME'),
],
// Host step types: a list of classes extending RoundlyConsulting\Workflows\Steps\StepType.
'steps' => [],
// Subject types: a list of classes implementing Contracts\DescribesWorkflowSubject.
'subjects' => [],
// Laravel events mapped to trigger keys: [Event::class => 'request.submitted'], or
// [Event::class => ['key' => 'request.submitted', 'subject' => 'request', 'user' => 'user',
// 'payload' => ['amount', 'currency'], 'idempotency_key' => 'submissionId']], or a
// self-describing WorkflowEvent as [Event::class => '*']. Workflows::triggers()->map() and
// ->listen() do the same from a service provider.
'events' => [],
// The default timezone of a workflow version (blank = app.timezone).
'timezone' => env('WORKFLOWS_TIMEZONE'),
'engine' => [
// How long a claimed step may run before wake reclaims it (the job timeout is 30 s less).
'lease' => 'PT10M',
// A queued step whose job was pushed longer ago than this is pushed again by wake.
'requeue_after' => 'PT5M',
],
'wake' => [
'batch' => 500,
'claim_ttl' => 'PT10M',
],
'retry' => [
'default' => [
'max_attempts' => 3,
'backoff' => [30, 120, 600],
'jitter' => 0.1,
],
'max_attempts_cap' => 10,
],
'limits' => [
'max_steps' => 200,
'max_depth' => 3,
// Instances a definition may start per minute; blank = 60, `off` = no limit.
'max_starts_per_minute' => env('WORKFLOWS_MAX_STARTS_PER_MINUTE', 60),
'max_loop_iterations' => 1000,
],
'graph' => [
'max_nodes' => 500,
'max_edges' => 2000,
'max_bytes' => 524288,
],
'conditions' => [
'max_depth' => 6,
'max_clauses' => 100,
],
'steps_output' => [
'max_bytes' => 65536,
],
// Each step run records its input: the node config with every value reference resolved,
// as the handler saw it. A larger input is stored as {"truncated": true, "bytes": n}.
'steps_input' => [
'max_bytes' => 65536,
],
'escalations' => [
'max_levels' => 5,
],
'idempotency' => [
// Trigger keys expire after this; a key re-used later starts a new instance.
'ttl' => 'P30D',
],
'schedule' => [
// Missed schedule slots within this window are coalesced into one start.
'catch_up' => 'PT1H',
],
'authorization' => [
// class-string<Contracts\AuthorizesSteps>: called before every side-effect step and escalation
// action, a null ability included (the default allows that).
'authorizer' => GateStepAuthorizer::class,
// Step type key => policy ability, overriding the type's own ability().
'abilities' => [],
],
'actor' => [
// class-string of an invokable returning the service-account user the `system` actor
// authorizes as (null: a null user, so policies deny unless they accept ?User).
'system_user' => null,
],
'owners' => [
// class-string<Contracts\RestoresOwnerContext>; null = teams when installed, else none.
'context' => null,
// class-string<Contracts\ChecksOwnerMembership>; null = teams when installed, else allow.
'membership' => null,
],
'parties' => [
// The user model `{"kind":"user"}` parties resolve to (null = auth.providers.users.model).
'user_model' => null,
// class-string<Contracts\ResolvesRoles>; null = teams when installed, else no roles.
'roles' => null,
],
'adapters' => [
// class-string<Contracts\TransitionAdapter>; null = the lifecycle bridge when installed.
'transition' => null,
// class-string<Contracts\DeliversWebhooks>; null = no outbound webhook step.
'webhooks' => null,
],
'business_time' => [
// ISO weekday numbers of the built-in `weekdays` calendar (1 = Monday).
'weekdays' => [1, 2, 3, 4, 5],
'max_search_days' => 366,
// class-string of an invokable returning the owner model of app-wide definitions'
// opening-hours calendars.
'calendar_owner' => null,
],
'approval' => [
// Safety net after an approval round's expiry, in case its resolution event was lost.
'expiry_grace' => 'PT5M',
],
// What happens to running instances when their subject is deleted: cancel | keep.
'subjects_on_deleted' => 'cancel',
'bridges' => [
'lifecycle' => [
// Emit `lifecycle.<lifecycle>.<transition>` for every lifecycle state change.
'emit_transitions' => env('WORKFLOWS_LIFECYCLE_EMIT_TRANSITIONS', 'off'),
],
],
// Definition files (`workflows:sync` / `workflows:export`): absolute or relative to the base path.
'sync' => [
'path' => env('WORKFLOWS_SYNC_PATH', 'resources/workflows'),
],
'dry_run' => [
// Write a workflow_dry_runs row for every dry run (on | off).
'log' => env('WORKFLOWS_DRY_RUN_LOG', 'off'),
],
'webhooks' => [
// The opt-in inbound start route: POST {prefix}/hooks/{hook}.
'enabled' => env('WORKFLOWS_WEBHOOKS_ENABLED', 'off'),
'prefix' => 'workflows',
'middleware' => ['api'],
// REQUIRED when enabled: the signature check (e.g. 'sentinel.signed:<profile>'). An
// empty list keeps the route unregistered (fail closed).
'verify_middleware' => [],
'max_bytes' => 262144,
],
'resources' => [
// How a host model renders. Point a key at your own JsonResource to add a name or avatar.
'owner' => WorkflowOwnerResource::class, // receives the owner model
'subject' => WorkflowSubjectResource::class, // receives the subject model
'user' => WorkflowUserResource::class, // receives a user model
],
'prune' => [
'instances_after' => 'P90D',
'dry_runs_after' => 'P30D',
],
];Typy kľúčov, modely a tabuľky
| Kľúč | Env | Predvolené | Povolené | Význam |
|---|---|---|---|---|
key_type | WORKFLOWS_KEY_TYPE | bigint | bigint, uuid, ulid | Kľúče používateľských morph stĺpcov (started_by, published_by, requested_by). |
owner_key_type | WORKFLOWS_OWNER_KEY_TYPE | = key_type | bigint, uuid, ulid | Kľúče morph stĺpcov vlastníka. |
subject_key_type | WORKFLOWS_SUBJECT_KEY_TYPE | = key_type | bigint, uuid, ulid | Kľúče morph stĺpcov subjektu; každý registrovaný typ subjektu mu musí zodpovedať. |
primary_key_type | WORKFLOWS_PRIMARY_KEY_TYPE | bigint | bigint, uuid, ulid | Vlastné id tabuliek balíka. |
models.* | — | packaged models | a subclass of the packaged model | Výmena modelu: rozšírte ho a uveďte podtriedu (definition, version, instance, step_run, wait, escalation, idempotency_key, dry_run). |
tables.* | — | workflow_* | ^[a-z][a-z0-9_]{0,39}$ | Názvy tabuliek: definitions, versions, instances, step_runs, waits, escalations, idempotency_keys, dry_runs. |
Front, registre a čas
| Kľúč | Env | Predvolené | Povolené | Význam |
|---|---|---|---|---|
queue.enabled | WORKFLOWS_QUEUE_ENABLED | on | boolean (on/off, true/false, 1/0) | Vypnuté = kroky bežia priamo v požiadavke. |
queue.connection | WORKFLOWS_QUEUE_CONNECTION | app default | string | Kam idú joby. |
queue.queue | WORKFLOWS_QUEUE_NAME | app default | string | Názov frontu. |
steps | — | [] | list of StepType class-strings | Triedy vlastných typov krokov. |
subjects | — | [] | list of DescribesWorkflowSubject class-strings | Typy subjektov (a vlastníkov). |
events | — | [] | map | Laravel udalosť → kľúč spúšťača: kľúč, '*' pre WorkflowEvent alebo {key, subject, user, payload, idempotency_key}. |
timezone | WORKFLOWS_TIMEZONE | app.timezone | IANA timezone | Predvolené časové pásmo verzie. |
Engine, prebúdzanie a opakovania
| Kľúč | Env | Predvolené | Povolené | Význam |
|---|---|---|---|---|
engine.lease | — | PT10M | 60 s – 1 day | Ako dlho smie prevzatý krok bežať (timeout jobu = lease − 30 s). |
engine.requeue_after | — | PT5M | 60 s – 1 day | Znova odošle krok vo fronte, ktorého job je starší. |
wake.batch | — | 500 | 1 – 10 000 | Počet riadkov prevzatých v jednom prechode (a strop for_each na jeden termín). |
wake.claim_ttl | — | PT10M | 60 s – 1 day | Staršie prevzatie sa vráti späť. |
retry.default.max_attempts | — | 3 | 1 – max_attempts_cap | Predvolený počet pokusov. |
retry.default.backoff | — | [30, 120, 600] | list of 0 – 86 400 s | Sekundy pred 2., 3., … pokusom; posledná hodnota sa opakuje. |
retry.default.jitter | — | 0.1 | 0.0 – 1.0 | Náhodný rozptyl každého odstupu. |
retry.max_attempts_cap | — | 10 | 1 – 100 | Horná hranica pre akúkoľvek politiku. |
Limity
| Kľúč | Env | Predvolené | Povolené | Význam |
|---|---|---|---|---|
limits.max_steps | — | 200 | 2 – 100 000 | Kroky na jednu inštanciu. |
limits.max_depth | — | 3 | 0 – 50 | Vnorenie cez start_workflow. |
limits.max_starts_per_minute | WORKFLOWS_MAX_STARTS_PER_MINUTE | 60 | 1 – 1 000 000, or off / none / null | Na definíciu; off = bez limitu. |
limits.max_loop_iterations | — | 1000 | 1 – 100 000 | Strop pre loop.max. |
graph.max_nodes | — | 500 | 2 – 10 000 | Uzly v grafe. |
graph.max_edges | — | 2000 | 1 – 100 000 | Hrany v grafe. |
graph.max_bytes | — | 524 288 (512 KiB) | 1 KiB – 16 MiB | Veľkosť zakódovaného grafu. |
conditions.max_depth | — | 6 | 1 – 32 | Vnorenie podmienok. |
conditions.max_clauses | — | 100 | 1 – 10 000 | Klauzuly v jednej podmienke. |
steps_output.max_bytes | — | 65 536 (64 KiB) | 256 B – 16 MiB | Strop výstupu kroku. |
steps_input.max_bytes | — | 65 536 (64 KiB) | 1 KiB – 1 MiB | Strop zaznamenaného vstupu kroku; väčší vstup sa uloží ako {"truncated": true, "bytes": n}. |
escalations.max_levels | — | 5 | 1 – 20 | Úrovne eskalácie na uzol. |
idempotency.ttl | — | P30D | 60 s – 366 days | Životnosť kľúča spúšťača. |
schedule.catch_up | — | PT1H | 60 s – 1 day | Zmeškané termíny v tomto okne sa zlúčia do jedného spustenia. |
Autorizácia, vlastníci, strany a adaptéry
| Kľúč | Env | Predvolené | Povolené | Význam |
|---|---|---|---|---|
authorization.authorizer | — | GateStepAuthorizer | AuthorizesSteps class-string | Autorizačný hook. |
authorization.abilities | — | [] | map of step type key → ability | Prepíše ability() typu kroku. |
actor.system_user | — | null | invokable class-string | Vráti servisný účet, pod ktorým sa autorizuje systémový aktér. |
owners.context | — | teams or none | RestoresOwnerContext class-string | Kontext vlastníka okolo každého jobu. |
owners.membership | — | teams or allow | ChecksOwnerMembership class-string | Kontrola členstva strán. |
parties.user_model | — | auth.providers.users.model | model class-string | Model, na ktorý sa vyhodnocujú strany typu user. |
parties.roles | — | teams or none | ResolvesRoles class-string | Vyhodnocovanie strán typu role. |
adapters.transition | — | lifecycle bridge | TransitionAdapter class-string | Adaptér kroku transition. |
adapters.webhooks | — | null | DeliversWebhooks class-string | Zaregistruje krok webhook na odchádzajúce volania. |
Pracovný čas, schvaľovanie a subjekty
| Kľúč | Env | Predvolené | Povolené | Význam |
|---|---|---|---|---|
business_time.weekdays | — | [1, 2, 3, 4, 5] | ISO weekdays 1 – 7 | Dni kalendára weekdays (duplicity sa vynechajú). |
business_time.max_search_days | — | 366 | 7 – 3660 | Hranica každého hľadania pracovného času, ktoré robí hodiny balíka; kalendáre opening_hours: používajú opening-hours.search_days. |
business_time.calendar_owner | — | null | invokable class-string | Vráti vlastníka kalendára pre definície platné pre celú aplikáciu. |
approval.expiry_grace | — | PT5M | 0 – 1 day | Poistné oneskorenie po vypršaní schvaľovania. |
subjects_on_deleted | — | cancel | cancel, keep | Čo sa stane s bežiacimi inštanciami zmazaného subjektu. |
bridges.lifecycle.emit_transitions | WORKFLOWS_LIFECYCLE_EMIT_TRANSITIONS | off | boolean | Pri každej zmene stavu lifecycle vyšle lifecycle.<lifecycle>.<transition>. |
Súbory, skúšobné behy, webhooky, resources a čistenie
| Kľúč | Env | Predvolené | Povolené | Význam |
|---|---|---|---|---|
sync.path | WORKFLOWS_SYNC_PATH | resources/workflows | absolute, or relative to the base path | Kde workflows:sync a workflows:export čítajú a zapisujú súbory definícií. |
dry_run.log | WORKFLOWS_DRY_RUN_LOG | off | boolean | Zaznamená každý skúšobný beh. |
webhooks.enabled | WORKFLOWS_WEBHOOKS_ENABLED | off | boolean | Prichádzajúca route. |
webhooks.prefix | — | workflows | string (slashes trimmed) | Prefix route. |
webhooks.middleware | — | ['api'] | list of middleware | Middleware route. |
webhooks.verify_middleware | — | [] | list of middleware | Povinné pri zapnutí: kontrola podpisu; prázdne ponechá route nezaregistrovanú. |
webhooks.max_bytes | — | 262 144 (256 KiB) | 256 B – 16 MiB | Strop tela požiadavky (nad ním 413). |
resources.owner / subject / user | — | packaged reference resources | instantiable JsonResource subclass | Nahraďte vlastnými, ak chcete pridať meno alebo avatar. |
prune.instances_after | — | P90D | 1 hour – 10 years | Doba uchovania ukončených inštancií. |
prune.dry_runs_after | — | P30D | 1 hour – 10 years | Doba uchovania záznamov skúšobných behov. |
Prostredie
WORKFLOWS_KEY_TYPE=bigint
WORKFLOWS_OWNER_KEY_TYPE=
WORKFLOWS_SUBJECT_KEY_TYPE=
WORKFLOWS_PRIMARY_KEY_TYPE=bigint
WORKFLOWS_QUEUE_ENABLED=true
WORKFLOWS_QUEUE_CONNECTION=
WORKFLOWS_QUEUE_NAME=
WORKFLOWS_TIMEZONE=
WORKFLOWS_MAX_STARTS_PER_MINUTE=60
WORKFLOWS_LIFECYCLE_EMIT_TRANSITIONS=off
WORKFLOWS_SYNC_PATH=resources/workflows
WORKFLOWS_DRY_RUN_LOG=off
WORKFLOWS_WEBHOOKS_ENABLED=offPrejavte lásku k open source
Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.
Ďalšie spôsoby podpory vrátane kryptomienOdoslaním daru súhlasíte s našimi podmienkami prijímania darov.
Chcete to zabudovať do svojho produktu?
Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.