
# Maszyny stanów

Maszyny stanów i przepływy pracy rozwiązują różne problemy.

Przepływ pracy odpowiada na pytanie: „jakie zadanie wykonać dalej?”. Maszyna stanów odpowiada na pytanie: „w jakim stanie znajduje się ten obiekt i jakie zdarzenia są teraz dozwolone?”. Ta różnica ma znaczenie, gdy budowany system nie jest tylko sekwencją kroków, lecz długotrwałym obiektem, który z czasem reaguje na dane z zewnątrz, takim jak sesja agenta, wątek czatu, cykl przeglądu, zgłoszenie lub proces zatwierdzania.

## Szybki przykład

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

Ta maszyna rozpoczyna w `awaiting_user`, przechodzi do `planning` po otrzymaniu wiadomości od użytkownika, pozwala zakolejkowanej akcji wyemitować `planned`, a następnie czeka w `awaiting_review`, aż zewnętrzne zatwierdzenie zakończy sesję. Najważniejsze nie jest samo składniowe ujęcie kodu, lecz to, że cykl życia jest jawny, możliwy do sprawdzenia i sterowany zdarzeniami.

## Jak działa maszyna

Po wysłaniu instancji maszyny Queuety zapisuje bieżącą nazwę stanu, publiczny ładunek stanu, wersję i skrót definicji, prawidłowe zdarzenia wejściowe dla bieżącego stanu oraz trwałą oś czasu zdarzeń.

Jeśli nowo osiągnięty stan ma przypisaną akcję `action()`, Queuety umieszcza w kolejce zadanie wejścia w stan. Akcja może po prostu zaktualizować publiczny stan i pozostawić maszynę w oczekiwaniu na następne zdarzenie albo wyemitować `_event` i opcjonalnie `_event_payload`, aby natychmiast zainicjować kolejne przejście. Jeśli stan nie ma akcji ani statusu końcowego, maszyna czeka na zdarzenia zewnętrzne wysyłane za pomocą `Queuety::machine_event()`.

## Wybór między przepływami pracy a maszynami stanów

Użyj przepływu pracy, gdy przebieg składa się przede wszystkim z kolejnych kroków. Pobierz dane, wykonaj każdą pracę, poczekaj, opracuj wynik, zakończ. Ten model sprawdza się, gdy istnieje wyraźny początek i koniec, a główne pytanie dotyczy tego, co wykonać dalej.

Użyj maszyny stanów, gdy prawidłowe działanie zależy od bieżącej fazy cyklu życia. To lepszy wybór, gdy zdarzenia mogą nadejść w różnej kolejności, obiekt może istnieć długo lub potrzebujesz jawnego wglądu w cykl życia obejmujący stany takie jak `awaiting_user`, `planning`, `running_agents`, `awaiting_review` i `completed`.

## Jak współpracują oba rozwiązania

Oba mechanizmy najlepiej sprawdzają się razem, a nie jako konkurencyjne rozwiązania. Akcja stanu może wysłać przepływ pracy, gdy przejście wymaga bardziej złożonego wykonania, a przepływ pracy może po zakończeniu emitować zdarzenie do maszyny. W praktyce maszyna stanów zarządza cyklem życia, a przepływy pracy wykonują kosztowne lub ściśle ustrukturyzowane operacje.

## Struktura konstruktora

`StateMachineBuilder` ma celowo niewielki zakres. `initial()` i `state()` definiują graf cyklu życia. `action()` dołącza zakolejkowaną pracę do jednego stanu. `on()` określa, które zdarzenia mogą przenieść maszynę do następnego stanu. `on_queue()`, `with_priority()` i `max_attempts()` określają sposób wykonywania akcji stanu, a `version()` i `idempotency_key()` dołączają trwałe metadane wysyłania. `dispatch()` tworzy instancję maszyny.

Akcje stanów mogą również udostępniać opcjonalną metodę `config()`, korzystającą z tych samych kluczy zasad dotyczących zasobów co kroki i programy obsługi przepływu pracy. Dzięki temu kosztowne przejście stanu może należeć do wspólnej grupy współbieżności albo otrzymać wyższą wagę kosztu, gdy akcja zużywa większą część budżetu niż zwykły krok.

Szerszy model zasobów opisano w sekcji [Zarządzanie zasobami](https://queuety.inline0.dev/pl/docs/features/resource-management).

## Kontrakty

Akcje wejścia w stan implementują `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` to uporządkowany ładunek z definicji akcji; jest pusty, jeśli jako akcję podano zwykłą nazwę klasy. Queuety tworzy akcje za pomocą `new $class()`, dlatego klasa akcji musi mieć konstruktor bez wymaganych argumentów.

Akcje stanów mogą również definiować opcjonalną metodę `config()` z `concurrency_group`, `concurrency_limit` i `cost_units`, jeśli zakolejkowana akcja wejścia ma uwzględniać dopuszczanie przez pracownika, ważone limity kolejek lub dostawców oraz inne zasady dotyczące zasobów.

Warunki przejścia implementują `Queuety\Contracts\StateGuard`:

```php
namespace Queuety\Contracts;

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

## Interfejsy inspekcji

Użyj fasady, aby sprawdzić działające maszyny:

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

Maszyny stanów nie mają poleceń WP-CLI: `wp queuety workflow ...` obsługuje tylko przepływy pracy. Użyj tych interfejsów API PHP, na przykład za pośrednictwem `wp eval`, aby sprawdzać maszyny z wiersza poleceń.

Te interfejsy API udostępniają bieżącą nazwę stanu, status cyklu życia, stan publiczny, dostępne zdarzenia, metadane definicji, pełną oś czasu przejść oraz ujednolicony pakiet śledzenia dla interfejsów debuggera. Wiersze listy maszyn zawierają wersję definicji, jej skrót i klucz idempotencji, dzięki czemu ekrany listy mogą wyświetlać wersję źródłową i uruchomieniową bez wczytywania każdej maszyny osobno. Pakiet śledzenia obejmuje pogrupowane stany, surowe zdarzenia, powiązane zadania akcji, dzienniki, odwołania do artefaktów i fragmentów, dane wejściowe i wyjściowe programów obsługi, stan przed i po zmianie, kontekst, czasy oraz uporządkowane błędy.

## Sesje agentów

Maszyny stanów są szczególnie przydatne w systemach agentów, które bardziej przypominają sesje niż potoki. Sesję przechodzącą przez `awaiting_user`, `planning`, `running_agents`, `awaiting_review` i `completed` zwykle łatwiej opisać jako jawny cykl życia niż jako jedną bardzo długą definicję przepływu pracy z licznymi oczekiwaniami i przejściami wstecz.

## Zobacz także

- [NeuronMaszyna stanów sesji](https://queuety.inline0.dev/pl/docs/examples/neuron-session-state-machine)
- [NeuronMaszyna stanów pamięci i przeglądu](https://queuety.inline0.dev/pl/docs/examples/neuron-memory-review)
- [Orkiestracja agentów](https://queuety.inline0.dev/pl/docs/workflows/agent-orchestration)
- [Sygnały przepływu pracy](https://queuety.inline0.dev/pl/docs/workflows/signals)
- [Zależności przepływu pracy](https://queuety.inline0.dev/pl/docs/workflows/dependencies)
- [Powtórzenia](https://queuety.inline0.dev/pl/docs/workflows/repeats)
- [Artefakty](https://queuety.inline0.dev/pl/docs/features/artifacts)
- [ PHP API](https://queuety.inline0.dev/pl/docs/api)
