Ga naar de inhoud

Toestandsmachines

Toestandsmachines en workflows lossen verschillende problemen op.

Een workflow beantwoordt de vraag: "welk werk wordt hierna uitgevoerd?" Een toestandsmachine beantwoordt: "in welke toestand bevindt dit object zich en welke gebeurtenissen zijn vanaf hier geldig?" Dat verschil is belangrijk wanneer wat u bouwt niet alleen een reeks stappen is, maar een entiteit met een lange levensduur die na verloop van tijd op externe invoer reageert, zoals een agentsessie, een chatthread, een beoordelingslevenscyclus, een ticket of een goedkeuringsproces.

Snel voorbeeld

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

Deze machine begint in awaiting_user, gaat naar planning wanneer een gebruikersbericht binnenkomt, laat de wachtrijactie planned uitsturen en wacht vervolgens in awaiting_review totdat een externe goedkeuring de sessie voltooit. Het belangrijkste is niet de codesyntaxis op zichzelf, maar dat de levenscyclus expliciet, inzichtelijk en gebeurtenisgestuurd is.

Hoe een machine werkt

Wanneer een machine-instantie wordt gedispatcht, slaat Queuety de huidige toestandsnaam, de publieke toestandspayload, de definitieversie en -hash, de geldige inkomende gebeurtenissen voor de huidige toestand en een duurzame gebeurtenistijdlijn op.

Als de toestand die wordt betreden een action() heeft, plaatst Queuety een taak voor die toestand in de wachtrij. Die actie kan simpelweg de publieke toestand bijwerken en de machine laten wachten op de volgende gebeurtenis, of _event en optioneel _event_payload uitsturen om de volgende overgang meteen te activeren. Als de toestand geen actie en geen terminale status heeft, wacht de machine gewoon op externe gebeurtenissen die met Queuety::machine_event() worden verzonden.

Kiezen tussen workflows en toestandsmachines

Gebruik een workflow wanneer de uitvoering in wezen uit stappen bestaat: gegevens ophalen, voor elk item wachten, samenvoegen en afronden. Dit model past goed wanneer er een duidelijk begin en einde is en de belangrijkste vraag is welk werk hierna moet worden uitgevoerd.

Gebruik een toestandsmachine wanneer geldig gedrag afhangt van de huidige levenscyclusfase. Dat past beter wanneer gebeurtenissen in verschillende volgordes kunnen binnenkomen, wanneer de entiteit lang kan bestaan of wanneer u de levenscyclus expliciet wilt kunnen bekijken met toestanden zoals awaiting_user, planning, running_agents, awaiting_review en completed.

Hoe de twee samenwerken

De twee bouwstenen werken het best samen, in plaats van met elkaar te concurreren. Een toestandactie kan een workflow dispatchen wanneer een overgang zwaardere uitvoering vereist, en een workflow kan na afloop van dat werk een gebeurtenis terugsturen naar een machine. In de praktijk kan de toestandsmachine zo de levenscyclus beheren, terwijl workflows de kostbare of sterk gestructureerde uitvoering verzorgen.

Opbouw van de builder

StateMachineBuilder blijft bewust klein. initial() en state() definiëren de levenscyclusgraaf. action() koppelt werk in de wachtrij aan één toestand. on() geeft aan welke gebeurtenissen de machine naar de volgende toestand kunnen brengen. on_queue(), with_priority() en max_attempts() bepalen hoe toestandacties worden uitgevoerd, terwijl version() en idempotency_key() duurzame dispatchmetadata toevoegen. dispatch() maakt de machine-instantie aan.

Toestandacties kunnen ook een optionele methode config() aanbieden, met dezelfde sleutels voor resourcebeleid als workflowstappen en handlers. Zo kunt u één kostbare toestandsovergang binnen een gedeelde concurrencygroep houden of een hoger kostengewicht toekennen wanneer een actie meer budget verbruikt dan een normale stap.

Het bredere resourcemodel wordt beschreven in Resourcebeheer.

Contracten

Acties bij het betreden van een toestand implementeren 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 is de gestructureerde payload uit de actiedefinitie, en is leeg wanneer de actie als een gewone klassenaam is opgegeven. Queuety maakt acties aan met new $class(), dus een actieklasse moet een constructor zonder verplichte argumenten hebben.

Toestandacties kunnen ook een optionele methode config() definiëren met concurrency_group, concurrency_limit en cost_units, wanneer de invoeractie uit de wachtrij moet deelnemen aan worker-toelating, gewogen wachtrij- of providerbudgetten en ander resourcebeleid.

Overgangsvoorwaarden implementeren Queuety\Contracts\StateGuard:

PHP
namespace Queuety\Contracts;

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

Inspectie-API's

Gebruik de facade om actieve machines te inspecteren:

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

Toestandsmachines hebben geen WP-CLI-opdrachten: wp queuety workflow ... geldt alleen voor workflows. Gebruik deze PHP-API's, bijvoorbeeld via wp eval, om machines vanaf de opdrachtregel te inspecteren.

Deze API's tonen de huidige toestandsnaam, levenscyclusstatus, publieke toestand, beschikbare gebeurtenissen, definitiemetadata, de volledige overgangstijdlijn en een genormaliseerde tracebundel voor debugger-UI's. Rijen met machinevermeldingen bevatten de definitieversie, definitiehash en idempotentiesleutel, zodat lijstschermen de bron-/runtimeversie kunnen tonen zonder elke machine afzonderlijk te laden. De tracebundel bevat gegroepeerde toestanden, ruwe gebeurtenissen, gekoppelde actietaken, logs, artefactverwijzingen, chunkverwijzingen, handlerinvoer en -uitvoer, toestand vóór en na, context, tijdmetingen en gestructureerde fouten.

Agentsessies

Toestandsmachines zijn bijzonder nuttig voor agentsystemen die meer op sessies dan op pijplijnen lijken. Een sessie die door awaiting_user, planning, running_agents, awaiting_review en completed gaat, is meestal eenvoudiger te begrijpen als een expliciete levenscyclus dan als één zeer lange workflowdefinitie met veel wachttijden en teruglussen.

Zie ook