
# 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

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

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](https://queuety.inline0.dev/de/docs/features/resource-management) beschrieben.

## Verträge

Aktionen beim Zustandseintritt implementieren `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` 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`:

```php
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:

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

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.

## Siehe auch

- [Neuron-Sitzungszustandsautomat](https://queuety.inline0.dev/de/docs/examples/neuron-session-state-machine)
- [Neuron-Speicher- und Prüfzustandsautomat](https://queuety.inline0.dev/de/docs/examples/neuron-memory-review)
- [Agenten-Orchestrierung](https://queuety.inline0.dev/de/docs/workflows/agent-orchestration)
- [Workflow-Signale](https://queuety.inline0.dev/de/docs/workflows/signals)
- [Workflow-Abhängigkeiten](https://queuety.inline0.dev/de/docs/workflows/dependencies)
- [Wiederholungen](https://queuety.inline0.dev/de/docs/workflows/repeats)
- [Artefakte](https://queuety.inline0.dev/de/docs/features/artifacts)
- [PHP API](https://queuety.inline0.dev/de/docs/api)
