---
title: "Beh krokov (engine) — Workflows for Laravel | Roundly"
description: "Ako kroky bežia: joby a lease, dve transakcie na krok, čakania a workflows:wake, opakovania, idempotencia, limity, autorizácia a kontext vlastníka."
url: https://roundly-consulting.com/sk/open-source/navody/workflows-for-laravel/beh-krokov
language: sk
---

[Všetky balíky](https://roundly-consulting.com/sk/open-source.md)

[Workflows for Laravel](https://roundly-consulting.com/sk/open-source/navody/workflows-for-laravel.md)

# Beh krokov (engine)

## Joby

Tri joby nesú len id, majú tries = 1 (opakovania riadi engine), odosielajú sa po commite a používajú workflows.queue.connection / queue. Timeout jobu je engine.lease − 30 s. failed() jobu zaznamená timeout workera len cez compare-and-set na claim token pokusu a vypršaný lease, takže opätovne doručený job nikdy nenaplánuje opakovanie popri živom handleri:

| Job | Spúšťa |
| --- | --- |
| `RunStepJob(stepRunId)` | Jeden pokus kroku. |
| `ResumeStepJob(stepRunId, waitId, kind)` | Čakajúci krok, ktorého čakanie nastalo. |
| `FireEscalationJob(escalationId)` | Úroveň eskalácie. |

## Jeden krok, dve transakcie

- Prevzatie — v kontexte vlastníka inštancie: zamkne inštanciu, potom krok. Skončí, ak inštancia už nebeží ani nečaká alebo krok už nie je vo fronte (duplicitné doručenie). Krok označí ako running s novým claim\_token a lease\_until. Commit → StepStarted.
- Mimo zámku: overí vlastníka subjektu (owner\_mismatch → handler sa nespustí), pri typoch s vedľajšími efektmi spustí autorizačný hook a zavolá handle() alebo resume(). Vstavané kroky, ktoré pracujú len s databázou (condition, branch, set\_field, loop, end), bežia namiesto toho v transakcii záznamu, takže efekt a záznam sa potvrdia spolu.
- Záznam — zamkne inštanciu, potom krok; claim token musí stále sedieť, inak sa výsledok zahodí (stratený lease). Dokončenie: uloží výsledok a výstup, zruší eskalácie tejto návštevy a pokračuje po hrane. Čakanie: uloží riadky čakaní; inštancia je waiting. Zlyhanie: pozri opakovania.

Poradie zámkov: inštancia (rodič pred deťmi) → krok → čakanie / eskalácia. Žiadna transakcia nezamyká druhú inštanciu okrem rodič → dieťa (kaskádové zrušenie). Signály medzi inštanciami sa posielajú po commite.

## Čakania a workflows:wake

| Druh čakania | Nastane, keď |
| --- | --- |
| `timer` | due\_at ≤ teraz |
| `event` | emit() / signal() s jeho kľúčom a zodpovedajúcim subjektom toho istého vlastníka (a pri where aj zodpovedajúcim payloadom) |
| `condition` | Subjekt dostane touch alebo je čas na kontrolu a podmienka platí |
| `retry` | Splatné → spustí sa ďalší pokus |
| `timeout` | Splatné → resume() so signálom timeout |

Prevzatia sú prenosné compare-and-set (bez SKIP LOCKED), v dávkach po wake.batch; prevzatie staršie než wake.claim\_ttl sa vráti späť (prevzatá udalosť sa namiesto toho doručí znova). Čakanie, ktoré nastane, zruší svoje súrodenecké čakania (udalosť zruší svoj časový limit a naopak); čakanie, ktorého krok sa už posunul, sa zruší. Signál, ktorý dorazí počas behu kroku, ostane prevzatý: bežiaci pokus ho doručí, len čo krok znova začne čakať, alebo ho vyradí, ak sa krok posunie — jednorazový signál, napríklad koniec dieťaťa, sa tak nikdy nestratí.

workflows:wake v tomto poradí: znova doručí prevzaté udalosti, ktorých job na obnovenie sa stratil → vráti ostatné zastarané prevzatia → prevezme späť vypršané lease (pokus zlyhá s lease\_expired, opakovateľne) → znova odošle stratené joby (kroky vo fronte odoslané pred viac než engine.requeue\_after a probe čakajúceho kroku, ktorý nikto neprevzal) → splatné časovače, opakovania a limity → splatné kontroly podmienok → splatné eskalácie → plánované spúšťače. Vráti WakeReport (timers, retries, timeouts, polls, escalations, schedules, reclaimed, requeued). Wake sám nikdy nič o subjekte nevyhodnocuje: prácu odovzdá jobom, ktoré najprv obnovia kontext vlastníka. Workflows::wake($now) vykoná celý prechod v čase $now — čo vypršalo, časové pečiatky prevzatí, ktoré čakania sú splatné — a opakovanie, ktoré spustí, prebehne v tom istom prechode, aj keď je $now pred skutočným časom; workflows:wake žiadny čas neodovzdáva.

## Opakovania a zlyhanie

```jsonc
{ "id": "sync_erp", "type": "acme.sync_erp", "config": { },
  "retry": { "max_attempts": 5, "backoff": [10, 60, 300] } }    // the last value repeats

// in PHP: ->node('sync_erp', 'acme.sync_erp')->retry(5, [10, 60, 300])
```

- Politika: retry uzla → settings.retry → retry() typu → retry.default (max\_attempts: 3, backoff: \[30, 120, 600\] sekúnd, posledná hodnota sa opakuje, jitter: 0.1). max\_attempts obmedzuje retry.max\_attempts\_cap (10).
- Opakovateľné zlyhanie so zostávajúcimi pokusmi: krok je failed; nový pokus (attempt + 1, rovnaký idempotentný kľúč) sa naplánuje po odstupe (alebo po retryAfter, ak je neskôr). StepFailed{willRetry: true}.
- Zlyhané obnovenie sa opakuje ako obnovenie: ďalší pokus znova zavolá resume() s rovnakým signálom a so vstupom a výstupom, s ktorými krok čakal (uložené v resume\_signal). handle() už nikdy nespustí, takže doručená udalosť sa nestratí a časovač sa nespustí odznova.
- Trvalé zlyhanie alebo posledný pokus: inštancia je failed s failure\_code, failure\_message, failed\_node\_id; jej čakania a eskalácie sa zrušia; StepFailed, InstanceFailed.
- Nikdy sa neopakujú automaticky: authorization\_denied, owner\_mismatch, subject\_missing, invalid\_output, žiadny limit (okrem dieťaťa start\_workflow, ktoré odmietol limit spustení: taký krok alebo eskalácia sa opakuje ako child\_not\_started), no\_approvers, transition\_denied (ak lifecycle neurčí inak), StepFailedException a žiadna výnimka balíka, ktorú handler nechá uniknúť (krok zlyhá s jej vlastným kódom). Neznáme výnimky sa opakujú ako exception.
- Ručné opakovanie, Workflows::instances()->retry($instance): zlyhaná inštancia, ktorej posledný krok zlyhal, dostane pokus n + 1 (rovnaký kľúč) a pokračuje od tohto uzla. Krok, ktorému zlyhal handle(), spustí handle() znova (approvals znova načíta svoje kolo); krok, ktorému zlyhal resume(), sa znova obnoví s uloženým signálom — kľúčom a payloadom udalosti, rozhodnutím, časovým limitom — a so vstupom a výstupom, s ktorými čakal, presne ako pri automatickom opakovaní, takže na udalosť, ktorá už prišla, sa znova nečaká. Bez obmedzenia; InstanceRetried. Inak InstanceNotRetryableException — pri zlyhanej inštancii, ktorá nezlyhala na kroku, správa odporučí spustiť ju znova.
- Zrušenie, Workflows::instances()->cancel($instance, $reason): bežiaca alebo čakajúca inštancia sa zmení na cancelled. Najprv sa zrušia jej čakania a eskalácie, potom sa spustí hook cancel() živého kroku a potom sa zrušia deti spustené s wait: true. Handler, ktorý skončí po zrušení, má výsledok zahodený a hook cancel() kroku sa spustí znova. Ukončená inštancia vyhodí InstanceNotCancellableException.

## Idempotencia

- Jedna evidencia (workflow\_idempotency\_keys, len odtlačky), dva rozsahy: start (definícia + kľúč spúšťača — opakovaný kľúč vráti prvú inštanciu s created: false) a effect (idempotentný kľúč kroku + názov once() — opakovaný once() vráti uložený výsledok).
- Kľúč spustenia sa kontroluje pod zámkom definície a jedinečným indexom vo vlastnom savepointe: paralelné duplicity na PostgreSQL aj MySQL vrátia tú istú inštanciu.
- Kľúče spustení zo spúšťačov vypršia po idempotency.ttl (P30D) a vyčistia sa; kľúč použitý neskôr spustí novú inštanciu. Kľúče efektov a interné kľúče spustení enginu žijú tak dlho ako ich inštancia, takže ani ručné opakovanie po mesiacoch nič nezopakuje.

## Limity

| Limit | Konfigurácia (predvolené) | Zlyhanie |
| --- | --- | --- |
| Kroky na inštanciu | limits.max\_steps (200); settings.limits.max\_steps may lower it | Inštancia zlyhá so step\_limit\_exceeded. |
| Hĺbka vnorenia | limits.max\_depth (3; root = 0) | Rodičovský krok zlyhá s nesting\_depth\_exceeded. |
| Spustenia definície za minútu | limits.max\_starts\_per\_minute (60; off = none) | Inštancia sa vytvorí ako zlyhaná so start\_rate\_exceeded; spustenie vráti created: false, refused a jeho idempotentný kľúč ostane voľný (webhook route odpovie 429; krok alebo eskalácia start\_workflow sa opakuje s odstupom ako child\_not\_started). |
| Iterácie slučky | limits.max\_loop\_iterations (1000) | invalid\_config pri publikovaní. |
| Veľkosť grafu | graph.max\_nodes / max\_edges / max\_bytes | graph\_too\_large pri publikovaní. |
| Výstup kroku | steps\_output.max\_bytes (64 KiB) | Pokus zlyhá s invalid\_output. |

Každá správa o zlyhaní je preložená a uvádza limit aj jeho hodnotu.

## Aktér a autorizácia

- settings.actor: system (predvolené) alebo on\_behalf\_of používateľa, ktorý beh spustil. Spustenie on\_behalf\_of bez používateľa vyhodí MissingTriggeringUserException; plánované a webhook spúšťače ho používať nemôžu (actor\_requires\_user).
- Autorizačný hook (Contracts\\AuthorizesSteps, workflows.authorization.authorizer) beží pred každým krokom s vedľajšími efektmi a pred každou eskalačnou akciou — vždy, aj keď krok neuvádza žiadne oprávnenie. Oprávnenie je workflows.authorization.abilities.<type key>, inak ability() typu, inak null. Konfigurácia grafu oprávnenie zvoliť nemôže.
- Predvolený GateStepAuthorizer overí Gate::forUser($user)->inspect($ability, \[$subject\]) a oprávnenie null povolí (cieľový balík si prístup stráži sám); hook, ktorý zaregistrujete sami, dostane každé volanie vrátane tých s null a jeho zamietnutie ukončí krok zlyhaním.
- Systémový aktér sa autorizuje ako workflows.actor.system\_user (invokable, ktorá vráti servisný účet), inak ako používateľ null — policy v Laraveli používateľa null zamietnu, ak neprijímajú ?User. Fail closed.
- Zamietnutie ukončí krok s authorization\_denied a správou policy; nikdy sa neopakuje. Zamietnutá eskalačná akcia ukončí zlyhaním eskaláciu, nikdy krok.
- Prechody lifecycle sa vykonajú ako používateľ (by()) alebo systém (asSystem()), takže platia aj pravidlá aktéra v lifecycle. Každá udalosť inštancie nesie inštanciu ako $actor a DTO Actor ako $runAs.

```php
use Illuminate\Auth\Access\Response;
use RoundlyConsulting\Workflows\Contracts\AuthorizesSteps;
use RoundlyConsulting\Workflows\DataTransferObjects\StepAuthorization;
use RoundlyConsulting\Workflows\Support\GateStepAuthorizer;

final readonly class WorkflowStepAuthorizer implements AuthorizesSteps
{
    public function __construct(private GateStepAuthorizer $gate) {}

    public function authorize(StepAuthorization $authorization): Response
    {
        // Called before every side-effect step and escalation action, also when the ability is null.
        if ($authorization->instance->owner?->suspended_at !== null) {
            return Response::deny('This team is suspended.');
        }

        return $this->gate->authorize($authorization);
    }
}

// config/workflows.php
'authorization' => [
    'authorizer' => App\Workflows\WorkflowStepAuthorizer::class,
    'abilities' => ['set_field' => 'updatePriority'],   // step type key => policy ability
],
```

## Kontext vlastníka

Contracts\\RestoresOwnerContext::run(?Model $owner, Closure) obaľuje každý job, transakciu spustenia, rozoslanie emitu, opakovanie, zrušenie aj skúšobné behy. S nainštalovaným teams a tímom ako vlastníkom je to Teams::runAs($team, …); inak sa callback jednoducho spustí (vlastnú implementáciu pre iný model tenantov uvediete vo workflows.owners.context). Job odoslaný z požiadavky v tíme B pre inštanciu tímu A beží ako A. Subjekt sa načíta v tomto kontexte, takže subjekt viazaný na iný tím sa javí ako chýbajúci (subject\_missing).

## Prejavte 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 kryptomien](https://roundly-consulting.com/sk/podporte-nas.md)

Odoslaním daru súhlasíte s našimi [podmienkami prijímania darov](https://roundly-consulting.com/sk/podmienky-darov.md).

[Podporte našu open-source prácu (otvorí sa v novej karte)](https://donate.stripe.com/dRmeVe8FX5PF1Qd9pXcEw00) [Pridajte sa k nám na Patreone (otvorí sa v novej karte)](https://www.patreon.com/cw/roundly)

## 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.

[Ponuka do 48 hodín](https://roundly-consulting.com/sk/kontakt.md) [Prezrieť všetky balíky](https://roundly-consulting.com/sk/open-source/navody/workflows-for-laravel.md)
