Zustandsautomaten
Zustandsautomaten und Workflows lösen unterschiedliche Probleme.
Ein Workflow beantwortet die Frage: „Welche Arbeit wird als Nächstes ausgeführt?“ Ein Zustandsautomat beantwortet: „In welchem Zustand befindet sich dieses Objekt, und welche Ereignisse sind von hier aus gültig?“ Dieser Unterschied ist wichtig, wenn du keine bloße Abfolge von Schritten erstellst, sondern ein langlebiges Objekt, das im Lauf der Zeit auf externe Eingaben reagiert, etwa eine Agentensitzung, einen Chatverlauf, einen Prüfablauf, ein Ticket oder einen Genehmigungsprozess.
Schnellstart-Beispiel
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' ]
);
Dieser Automat beginnt in awaiting_user und wechselt in planning, sobald eine Nutzernachricht eintrifft. Dann kann die Aktion in der Warteschlange planned ausgeben. Anschließend wartet der Automat in awaiting_review, bis eine externe Genehmigung die Sitzung abschließt. Entscheidend ist nicht allein die Codesyntax, sondern dass der Lebenszyklus explizit, nachvollziehbar und ereignisgesteuert ist.
So läuft ein Automat ab
Wenn eine Automateninstanz gesendet wird, speichert Queuety den aktuellen Zustandsnamen, die öffentlichen Zustandsdaten, die Definitionsversion und den Hash, die gültigen eingehenden Ereignisse für den aktuellen Zustand sowie eine dauerhafte Ereigniszeitachse.
Wenn der betretene Zustand eine action() hat, stellt Queuety einen Job für den Zustandseintritt in die Warteschlange. Diese Aktion kann einfach den öffentlichen Zustand aktualisieren und den Automaten auf das nächste Ereignis warten lassen. Sie kann aber auch _event ausgeben und optional _event_payload, damit sofort der nächste Übergang ausgeführt wird. Hat der Zustand keine Aktion und keinen Endstatus, wartet der Automat einfach auf externe Ereignisse, die mit Queuety::machine_event() gesendet werden.
Workflows oder Zustandsautomaten auswählen
Nutze einen Workflow, wenn der Ablauf grundsätzlich aus einzelnen Schritten besteht: Daten abrufen, für jede Arbeit warten, Ergebnisse zusammenführen und abschließen. Dieses Modell eignet sich, wenn es einen klaren Anfang und ein klares Ende gibt und vor allem die Frage zählt, welche Arbeit als Nächstes ausgeführt werden soll.
Nutze einen Zustandsautomaten, wenn das gültige Verhalten von der aktuellen Lebenszyklusphase abhängt. Er eignet sich besser, wenn Ereignisse in unterschiedlicher Reihenfolge eintreffen können, das Objekt lange bestehen kann oder du den Lebenszyklus mit Zuständen wie awaiting_user, planning, running_agents, awaiting_review und completed explizit prüfen musst.
So arbeiten beide zusammen
Die beiden Grundbausteine ergänzen sich am besten. Eine Zustandsaktion kann einen Workflow senden, wenn ein Übergang umfangreichere Ausführung erfordert. Ein Workflow kann nach Abschluss seiner Arbeit ein Ereignis an einen Automaten ausgeben. So steuert der Zustandsautomat in der Praxis den Lebenszyklus, während Workflows aufwendige oder stark strukturierte Aufgaben ausführen.
Aufbau des Builders
StateMachineBuilder ist bewusst einfach gehalten. initial() und state() definieren den Lebenszyklusgraphen. action() fügt einem Zustand eine Aufgabe in der Warteschlange hinzu. on() legt fest, welche Ereignisse den Automaten in den nächsten Zustand versetzen können. on_queue(), with_priority() und max_attempts() steuern die Ausführung von Zustandsaktionen, während version() und idempotency_key() dauerhafte Dispatch-Metadaten hinzufügen. dispatch() erstellt die Automateninstanz.
Zustandsaktionen können außerdem eine optionale Methode config() bereitstellen, die dieselben Richtlinienschlüssel für Ressourcen nutzt wie Workflow-Schritte und Handler. So kann ein aufwendiger Zustandsübergang in einer gemeinsamen Parallelitätsgruppe bleiben oder ein höheres Kostengewicht erhalten, wenn die Aktion mehr Budget verbraucht als ein gewöhnlicher Schritt.
Das umfassendere Ressourcenmodell wird unter Ressourcenverwaltung beschrieben.
Verträge
Aktionen beim Zustandseintritt implementieren Queuety\Contracts\StateAction:
namespace Queuety\Contracts;
interface StateAction {
public function handle( array $state, ?string $event = null, array $event_payload = [], array $payload = [] ): array|string;
}
$payload enthält die strukturierte Payload aus der Aktionsdefinition. Wurde die Aktion als einfacher Klassenname angegeben, ist sie leer. Queuety erstellt Aktionen mit new $class(). Daher benötigt eine Aktionsklasse einen Konstruktor ohne erforderliche Argumente.
Zustandsaktionen können außerdem eine optionale Methode config() mit concurrency_group, concurrency_limit und cost_units definieren, wenn die Aktion beim Zustandseintritt an der Zulassung durch Worker, an gewichteten Warteschlangen- oder Anbieterbudgets und an anderen Ressourcenrichtlinien teilnehmen soll.
Übergangswächter implementieren Queuety\Contracts\StateGuard:
namespace Queuety\Contracts;
interface StateGuard {
public function allows( array $state, array $event_payload, string $event, array $payload = [] ): bool;
}
APIs zur Prüfung
Nutze die Fassade, um laufende Automaten zu prüfen:
$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 );
Für Zustandsautomaten gibt es keine WP-CLI-Befehle: wp queuety workflow ... deckt nur Workflows ab. Nutze diese PHP-APIs, zum Beispiel über wp eval, um Automaten über die Kommandozeile zu prüfen.
Diese APIs stellen den aktuellen Zustandsnamen, den Lebenszyklusstatus, den öffentlichen Zustand, verfügbare Ereignisse, Metadaten zur Definition, die vollständige Übergangszeitachse und ein normalisiertes Trace-Paket für Debugger-UIs bereit. In den Zeilen der Automatenliste stehen Definitionsversion, Definitionshash und Idempotenzschlüssel. So können Listenansichten die Quell- und Laufzeitversion anzeigen, ohne jeden Automaten einzeln zu laden. Das Trace-Paket enthält gruppierte Zustände, unformatierte Ereignisse, zugehörige Aktionsjobs, Protokolle, Artefaktverweise, Chunk-Verweise, Handler-Eingaben und -Ausgaben, Zustände davor und danach, Kontext, Zeitmessungen sowie strukturierte Fehler.
Agentensitzungen
Zustandsautomaten sind besonders nützlich für Agentensysteme, die eher wie Sitzungen als wie Pipelines funktionieren. Eine Sitzung, die sich durch awaiting_user, planning, running_agents, awaiting_review und completed bewegt, lässt sich meist einfacher als expliziter Lebenszyklus verstehen denn als sehr lange Workflow-Definition mit vielen Wartezeiten und Rücksprüngen.