Hoppa till innehåll

Tillståndsmaskiner

Tillståndsmaskiner och arbetsflöden löser olika problem.

Ett arbetsflöde besvarar frågan ”vilket arbete körs härnäst?”. En tillståndsmaskin besvarar frågan ”vilket tillstånd befinner sig den här saken i, och vilka händelser är giltiga härifrån?”. Skillnaden är viktig när det du bygger inte bara är en sekvens av steg, utan en långlivad entitet som reagerar på yttre indata över tid, till exempel en agentsession, en chatttråd, en granskningslivscykel, ett ärende eller ett godkännandeflöde.

Snabbexempel

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' ]
);

Den här maskinen startar i awaiting_user, går över till planning när ett användarmeddelande kommer, låter den köade åtgärden skicka ut planned och väntar sedan i awaiting_review tills ett externt godkännande slutför sessionen. Det viktiga är inte själva kodsyntaxen, utan att livscykeln är uttrycklig, inspekterbar och händelsestyrd.

Så körs en maskin

När en maskininstans skickas ut sparar Queuety det aktuella tillståndsnamnet, den offentliga tillståndsnyttolasten, definitionens version och hash, giltiga inkommande händelser för det aktuella tillståndet samt en beständig händelsetidslinje.

Om det tillstånd som aktiveras har ett action() placerar Queuety ett jobb för tillståndsstart i kön. Åtgärden kan helt enkelt uppdatera det offentliga tillståndet och låta maskinen vänta på nästa händelse, eller skicka ut _event och eventuellt _event_payload för att genomföra nästa övergång direkt. Om tillståndet saknar åtgärd och terminalstatus väntar maskinen bara på externa händelser som skickas med Queuety::machine_event().

Välja mellan arbetsflöden och tillståndsmaskiner

Använd ett arbetsflöde när körningen i grunden är stegorienterad. Hämta data, bearbeta varje uppgift, vänta, sammanställ och avsluta. Den modellen passar bra när det finns en tydlig start och ett tydligt slut och huvudfrågan är vilket arbete som ska köras härnäst.

Använd en tillståndsmaskin när det giltiga beteendet beror på den aktuella livscykelfasen. Den passar bättre när händelser kan komma i olika ordning, när entiteten kan finnas kvar länge eller när du behöver kunna inspektera livscykeln med uttryckliga tillstånd som awaiting_user, planning, running_agents, awaiting_review och completed.

Så samverkar de

De två byggstenarna fungerar bäst tillsammans i stället för att konkurrera med varandra. En tillståndsåtgärd kan skicka ut ett arbetsflöde när en övergång kräver mer omfattande körning, och ett arbetsflöde kan skicka tillbaka en händelse till en maskin när arbetet är klart. I praktiken låter det tillståndsmaskinen styra livscykeln medan arbetsflöden utför det kostsamma eller starkt strukturerade arbetet.

Byggarens struktur

StateMachineBuilder är avsiktligt liten. initial() och state() definierar livscykelgrafen. action() kopplar köat arbete till ett tillstånd. on() anger vilka händelser som kan föra maskinen till nästa tillstånd. on_queue(), with_priority() och max_attempts() styr hur tillståndsåtgärder körs, medan version() och idempotency_key() kopplar till beständig metadata för utskick. dispatch() skapar maskininstansen.

Tillståndsåtgärder kan också ha en valfri metod config() med samma resursprincipnycklar som arbetsflödessteg och hanterare använder. Därmed går det att lägga en resurskrävande tillståndsövergång i en delad samtidighetsgrupp eller ange en högre kostnadsvikt när en åtgärd förbrukar mer av budgeten än ett normalt steg.

Den bredare resursmodellen beskrivs i Resurshantering.

Kontrakt

Åtgärder vid tillståndsstart implementerar 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 är den strukturerade nyttolasten från åtgärdsdefinitionen och är tom när åtgärden angavs som ett enkelt klassnamn. Queuety skapar åtgärder med new $class(), så en åtgärdsklass behöver en konstruktor utan obligatoriska argument.

Tillståndsåtgärder kan också definiera en valfri metod config() med concurrency_group, concurrency_limit och cost_units när den köade startåtgärden ska delta i arbetarinsläpp, viktade kö- eller leverantörsbudgetar och andra resursprinciper.

Övergångsvillkor implementerar Queuety\Contracts\StateGuard:

PHP
namespace Queuety\Contracts;

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

Inspektions-API:er

Använd fasaden för att inspektera maskiner som körs:

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 );

Tillståndsmaskiner har inga kommandon av typen WP-CLI: wp queuety workflow ... omfattar endast arbetsflöden. Använd dessa PHP-API:er, till exempel via wp eval, för att inspektera maskiner från kommandoraden.

Dessa API:er visar aktuellt tillståndsnamn, livscykelstatus, offentligt tillstånd, tillgängliga händelser, definitionsmetadata, hela övergångstidslinjen och ett normaliserat spårningspaket för felsökningsgränssnitt. Raderna i maskinlistan innehåller definitionens version, hash och idempotensnyckel, så att listvyer kan visa käll- och körningsversion utan att läsa in varje maskin individuellt. Spårningspaketet innehåller grupperade tillstånd, råa händelser, korrelerade åtgärdsjobb, loggar, artefaktreferenser, chunkreferenser, indata och utdata från hanterare, tillstånd före och efter, kontext, tidsangivelser och strukturerade fel.

Agentsessioner

Tillståndsmaskiner är särskilt användbara för agentsystem som fungerar mer som sessioner än som pipelines. En session som går genom awaiting_user, planning, running_agents, awaiting_review och completed är oftast enklare att förstå som en uttrycklig livscykel än som en mycket lång arbetsflödesdefinition med många väntelägen och återkopplingar.

Se även