Přejít k obsahu

Stavové automaty

Stavové automaty a workflow řeší různé problémy.

Workflow odpovídá na otázku „jaká práce se provede dál?“. Stavový automat odpovídá na otázku „v jakém stavu se tato věc nachází a jaké události jsou odtud platné?“. Na tomto rozdílu záleží, když vytváříte něco, co není jen posloupností kroků, ale dlouhodobě existující entitou, která v čase reaguje na vnější vstupy, například relaci agenta, chatové vlákno, proces kontroly, požadavek nebo schvalovací proces.

Rychlý příklad

PHP
use Queuety\Enums\StateMachineStatus;
use Queuety\Queuety;

$machine_id = Queuety::machine( 'agent_session' )
    ->version( 'agent-session.v1' )
    ->state( 'awaiting_user' )
    ->on( 'user_message', 'planning' )
    ->state( 'planning' )
    ->action( PlanSessionAction::class )
    ->on( 'planned', 'awaiting_review' )
    ->state( 'awaiting_review' )
    ->on( 'approve', 'completed', ReviewApprovedGuard::class )
    ->on( 'reject', 'awaiting_user' )
    ->state( 'completed', StateMachineStatus::Completed )
    ->dispatch( [ 'thread_id' => 42 ] );

Queuety::machine_event(
    $machine_id,
    'user_message',
    [ 'message' => 'Find competitors for this product' ]
);

Queuety::machine_event(
    $machine_id,
    'approve',
    [ 'approved' => true, 'reviewer' => 'editor@example.com' ]
);

Tento automat začíná ve stavu awaiting_user, po příchodu zprávy od uživatele přejde do planning, nechá zařazenou akci emitovat planned a poté čeká ve stavu awaiting_review, dokud externí schválení relaci nedokončí. Podstatná není samotná syntaxe kódu. Podstatné je, že životní cyklus je výslovně definovaný, lze jej kontrolovat a řídí se událostmi.

Jak automat funguje

Při odeslání instance automatu Queuety uloží název aktuálního stavu, veřejná data stavu, verzi a hash definice, platné příchozí události pro aktuální stav a trvalou časovou osu událostí.

Pokud má vstupovaný stav action(), Queuety zařadí úlohu pro vstup do stavu. Tato akce může jednoduše aktualizovat veřejný stav a nechat automat čekat na další událost, nebo může emitovat _event a případně také _event_payload, aby okamžitě provedla další přechod. Pokud stav nemá akci ani koncový stav, automat pouze čeká na externí události odeslané pomocí Queuety::machine_event().

Kdy zvolit workflow a kdy stavový automat

Workflow použijte, když běh vychází především z jednotlivých kroků. Načíst data, zpracovat každou položku, počkat, syntetizovat, dokončit. Tento model se hodí, když je jasný začátek i konec a hlavní otázkou je, jaká práce se má provést dál.

Stavový automat použijte, když platné chování závisí na aktuální fázi životního cyklu. Hodí se lépe, když události mohou přicházet v různém pořadí, entita může existovat dlouhou dobu nebo potřebujete výslovně kontrolovat její životní cyklus ve stavech jako awaiting_user, planning, running_agents, awaiting_review a completed.

Jak spolu oba přístupy fungují

Obě primitivní konstrukce fungují nejlépe společně, nikoli jako konkurující si řešení. Akce stavu může při přechodu vyžadujícím náročnější zpracování odeslat workflow a workflow může po dokončení práce emitovat událost zpět do automatu. V praxi tak stavový automat řídí životní cyklus, zatímco workflow provádějí náročné nebo vysoce strukturované úlohy.

Struktura builderu

StateMachineBuilder zůstává záměrně malý. initial() a state() definují graf životního cyklu. action() připojuje zařazenou práci k jednomu stavu. on() určuje, které události mohou přesunout automat do dalšího stavu. on_queue(), with_priority() a max_attempts() řídí vykonávání akcí stavu, zatímco version() a idempotency_key() připojují trvalá metadata odeslání. dispatch() vytvoří instanci automatu.

Akce stavu mohou také zpřístupnit volitelnou metodu config(), která používá stejné klíče zásad pro zdroje jako kroky a obsluhy workflow. Díky tomu lze náročný přechod stavu zařadit do sdílené skupiny souběžnosti nebo připojit vyšší váhovou hodnotu nákladů, když akce spotřebuje větší část rozpočtu než běžný krok.

Širší model zdrojů je popsán v části Správa zdrojů.

Kontrakty

Akce při vstupu do stavu implementují Queuety\Contracts\StateAction:

PHP
namespace Queuety\Contracts;

interface StateAction {
    public function handle( array $state, ?string $event = null, array $event_payload = [], array $payload = [] ): array|string;
}

$payload jsou strukturovaná data z definice akce; pokud byla akce zadána jako prostý název třídy, jsou prázdná. Queuety vytváří akce pomocí new $class(), takže třída akce potřebuje konstruktor bez povinných argumentů.

Akce stavu mohou také definovat volitelnou metodu config() s concurrency_group, concurrency_limit a cost_units, pokud se má zařazená akce při vstupu do stavu účastnit přijímání workerem, rozpočtů vážených front nebo poskytovatelů a dalších zásad pro zdroje.

Ochranné podmínky přechodů implementují Queuety\Contracts\StateGuard:

PHP
namespace Queuety\Contracts;

interface StateGuard {
    public function allows( array $state, array $event_payload, string $event, array $payload = [] ): bool;
}

Rozhraní pro kontrolu

Ke kontrole běžících automatů použijte fasádu:

PHP
$status   = Queuety::machine_status( $machine_id );
$machines = Queuety::list_machines();
$events   = Queuety::machine_timeline( $machine_id );
$trace    = Queuety::machine_trace( $machine_id );
$state    = Queuety::machine_state_at( $machine_id, $event_id );

Stavové automaty nemají příkazy WP-CLI: wp queuety workflow ... se týká pouze workflow. K jejich kontrole z příkazového řádku použijte tato rozhraní PHP, například prostřednictvím wp eval.

Tato rozhraní zpřístupňují název aktuálního stavu, stav životního cyklu, veřejný stav, dostupné události, metadata definice, úplnou časovou osu přechodů a normalizovaný balíček trasování pro uživatelská rozhraní debuggeru. Řádky seznamu automatů obsahují verzi definice, hash definice a idempotency key, takže seznamy mohou zobrazit zdrojovou a běhovou verzi, aniž by bylo nutné načítat každý automat zvlášť. Balíček trasování obsahuje seskupené stavy, nezpracované události, související úlohy akcí, protokoly, odkazy na artefakty, odkazy na části, vstup a výstup obsluhy, stav před a po, kontext, časové údaje a strukturované chyby.

Relace agentů

Stavové automaty jsou obzvlášť užitečné pro systémy agentů, které se podobají spíše relacím než pipeline. Relaci, která prochází stavy awaiting_user, planning, running_agents, awaiting_review a completed, lze obvykle snáze pochopit jako výslovný životní cyklus než jako jedinou velmi dlouhou definici workflow s mnoha čekáními a zpětnými přechody.

Viz také