Treci la conținut

Mașini de stări

Mașinile de stări și fluxurile de lucru rezolvă probleme diferite.

Un flux de lucru răspunde la întrebarea „ce activitate urmează?”. O mașină de stări răspunde la întrebarea „în ce stare se află acest lucru și ce evenimente sunt valide de aici?”. Diferența contează când ceea ce construiți nu este doar o succesiune de pași, ci o entitate cu durată lungă de viață care reacționează la intrări externe în timp, precum o sesiune de agent, un fir de conversație, un ciclu de revizuire, un tichet sau un flux de aprobare.

Exemplu rapid

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

Această mașină începe în awaiting_user, trece în planning când sosește un mesaj de la utilizator, permite acțiunii din coadă să emită planned, apoi așteaptă în awaiting_review până când o aprobare externă finalizează sesiunea. Ideea importantă nu este doar sintaxa codului, ci faptul că ciclul de viață este explicit, inspectabil și bazat pe evenimente.

Cum rulează o mașină

Când este trimisă o instanță a mașinii, Queuety persistă numele stării curente, payload-ul public al stării, versiunea și hash-ul definiției, evenimentele de intrare valide pentru starea curentă și o cronologie durabilă a evenimentelor.

Dacă starea accesată are un action(), Queuety adaugă în coadă un job de intrare în stare. Acțiunea poate doar să actualizeze starea publică și să lase mașina în așteptarea următorului eveniment sau poate emite _event și, opțional, _event_payload pentru a declanșa imediat tranziția următoare. Dacă starea nu are nicio acțiune și niciun statut terminal, mașina așteaptă pur și simplu evenimente externe trimise cu Queuety::machine_event().

Alegerea între fluxuri de lucru și mașini de stări

Folosiți un flux de lucru când execuția este, în esență, orientată spre pași. Preluați datele, procesați fiecare element, așteptați, sintetizați, finalizați. Acest model se potrivește când există un început și un sfârșit clar, iar întrebarea principală este ce activitate ar trebui executată în continuare.

Folosiți o mașină de stări când comportamentul valid depinde de etapa curentă a ciclului de viață. Se potrivește mai bine când evenimentele pot sosi în ordini diferite, când entitatea poate avea o durată lungă de viață sau când aveți nevoie de inspectarea explicită a ciclului de viață, cu stări precum awaiting_user, planning, running_agents, awaiting_review și completed.

Cum se completează reciproc

Cele două primitive funcționează cel mai bine împreună, nu în competiție. O acțiune de stare poate trimite un flux de lucru când o tranziție necesită o execuție mai amplă, iar un flux de lucru poate emite un eveniment înapoi către o mașină când activitatea respectivă este finalizată. În practică, astfel mașina de stări gestionează ciclul de viață, iar fluxurile de lucru execută activitățile costisitoare sau foarte structurate.

Structura constructorului

StateMachineBuilder este conceput să rămână compact. initial() și state() definesc graful ciclului de viață. action() atașează activități în coadă unei stări. on() declară ce evenimente pot muta mașina în starea următoare. on_queue(), with_priority() și max_attempts() controlează modul de executare a acțiunilor de stare, iar version() și idempotency_key() atașează metadatele durabile de trimitere. dispatch() creează instanța mașinii.

Acțiunile de stare pot expune și o metodă opțională config(), folosind aceleași chei de politică a resurselor ca pașii și handlerii fluxurilor de lucru. Astfel, o tranziție de stare costisitoare poate fi păstrată într-un grup comun de concurență sau i se poate atribui o pondere de cost mai mare când o acțiune consumă mai mult din buget decât un pas obișnuit.

Modelul mai amplu al resurselor este descris în Gestionarea resurselor.

Contracte

Acțiunile de intrare în stare implementează 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 este payload-ul structurat din definiția acțiunii și este gol când acțiunea a fost furnizată ca nume simplu de clasă. Queuety creează acțiuni cu new $class(), așadar o clasă de acțiune trebuie să aibă un constructor fără argumente obligatorii.

Acțiunile de stare pot defini și o metodă opțională config() cu concurrency_group, concurrency_limit și cost_units atunci când acțiunea de intrare pusă în coadă trebuie să participe la admiterea workerilor, la bugetele ponderate ale cozilor sau furnizorilor și la alte politici privind resursele.

Condițiile de tranziție implementează Queuety\Contracts\StateGuard:

PHP
namespace Queuety\Contracts;

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

API-uri de inspecție

Folosiți fațada pentru a inspecta mașinile în execuție:

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

Mașinile de stări nu au comenzi WP-CLI: wp queuety workflow ... acoperă numai fluxurile de lucru. Folosiți aceste API-uri PHP, de exemplu prin wp eval, pentru a inspecta mașinile din linia de comandă.

Aceste API-uri expun numele stării curente, statutul ciclului de viață, starea publică, evenimentele disponibile, metadatele definiției, cronologia completă a tranzițiilor și un pachet de urmărire normalizat pentru interfețele de depanare. Rândurile din lista mașinilor includ versiunea definiției, hash-ul definiției și cheia de idempotentă, astfel încât ecranele de listare să poată afișa versiunea sursei și a runtime-ului fără să încarce individual fiecare mașină. Pachetul de urmărire include stări grupate, evenimente brute, joburi de acțiune corelate, jurnale, referințe la artefacte și fragmente, intrarea și ieșirea handlerului, starea de dinainte și de după, contextul, timpii și erori structurate.

Sesiuni de agent

Mașinile de stări sunt deosebit de utile pentru sistemele cu agenți care funcționează mai degrabă ca sesiuni decât ca fluxuri de procesare. O sesiune care trece prin awaiting_user, planning, running_agents, awaiting_review și completed este de obicei mai ușor de înțeles ca un ciclu de viață explicit decât ca o singură definiție foarte lungă de flux de lucru, cu multe așteptări și reveniri.

Consultați și