
# Машини на състоянията

Машините на състоянията и работните потоци решават различни проблеми.

Работният поток отговаря на въпроса „каква работа се изпълнява след това?“. Машината на състоянията отговаря на въпросите „в какво състояние е този обект и кои събития са валидни оттук нататък?“. Тази разлика е важна, когато създавате не просто поредица от стъпки, а дълготраен обект, който с времето реагира на външни входни данни, например сесия на агент, чат нишка, цикъл на преглед, заявка за поддръжка или поток за одобрение.

## Кратък пример

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

Тази машина започва в `awaiting_user`, преминава в `planning` при получаване на потребителско съобщение, позволява на опашната задача да изпрати `planned` и след това изчаква в `awaiting_review`, докато външно одобрение завърши сесията. Важна е не толкова самата синтактична форма на кода, а това, че жизненият цикъл е явен, подлежи на проверка и се управлява от събития.

## Как работи една машина

При изпращане на екземпляр на машината Queuety запазва текущото име на състоянието, публичните данни за състоянието, версията и хеша на дефиницията, валидните входящи събития за текущото състояние и устойчивата времева линия на събитията.

Ако въведеното състояние има `action()`, Queuety поставя задача за влизане в състояние в опашката. Това действие може просто да актуализира публичното състояние и да остави машината да чака следващото събитие, или да изпрати `_event` и по желание `_event_payload`, за да задейства веднага следващия преход. Ако състоянието няма действие и не е крайно, машината просто чака външни събития, изпратени с `Queuety::machine_event()`.

## Избор между работни потоци и машини на състоянията

Използвайте работен поток, когато изпълнението по същество се състои от стъпки: извличане на данни, работа по всяка задача, изчакване, обобщаване и завършване. Този модел е подходящ, когато има ясен старт и край и основният въпрос е каква работа трябва да се изпълни след това.

Използвайте машина на състоянията, когато валидното поведение зависи от текущата фаза на жизнения цикъл. Тя е по-подходяща, когато събитията може да пристигат в различен ред, обектът може да съществува дълго време или ви е нужна явна проверка на жизнения цикъл със състояния като `awaiting_user`, `planning`, `running_agents`, `awaiting_review` и `completed`.

## Как работят заедно двата подхода

Двата примитива работят най-добре заедно, вместо да се конкурират. Действие на състояние може да изпрати работен поток, когато преходът изисква по-интензивно изпълнение, а работният поток може да изпрати събитие обратно към машина, когато тази работа приключи. На практика така машината на състоянията управлява жизнения цикъл, а работните потоци изпълняват скъпите или силно структурирани задачи.

## Структура на конструктора

`StateMachineBuilder` умишлено е опростен. `initial()` и `state()` дефинират графа на жизнения цикъл. `action()` прикачва задача от опашката към едно състояние. `on()` указва кои събития могат да преместят машината в следващото състояние. `on_queue()`, `with_priority()` и `max_attempts()` управляват изпълнението на действията на състоянията, а `version()` и `idempotency_key()` прикачват устойчиви метаданни за изпращане. `dispatch()` създава екземпляра на машината.

Действията на състоянията могат също да предоставят незадължителен метод `config()`, използващ същите ключове за правила за ресурсите като стъпките и обработчиците на работния поток. Така можете да включите скъп преход на състояние в споделена група за конкурентност или да зададете по-висока тежест на разхода, когато действието използва повече ресурс от обичайна стъпка.

По-широкият модел за ресурси е описан в [Управление на ресурсите](https://queuety.inline0.dev/bg/docs/features/resource-management).

## Договори

Действията при влизане в състояние имплементират `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` са структурирани данни от дефиницията на действието; те са празни, когато действието е зададено като обикновено име на клас. Queuety създава действия с `new $class()`, затова класът на действието трябва да има конструктор без задължителни аргументи.

Действията на състоянията могат също да дефинират незадължителен метод `config()` с `concurrency_group`, `concurrency_limit` и `cost_units`, когато опашното действие при влизане трябва да участва в допускането на задачи от работника, бюджетите за претеглени опашки или доставчици и други правила за ресурсите.

Ограниченията за преход имплементират `Queuety\Contracts\StateGuard`:

```php
namespace Queuety\Contracts;

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

## API за проверка

Използвайте фасадата, за да проверите работещите машини:

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

Машините на състоянията нямат команди WP-CLI: `wp queuety workflow ...` обхваща само работните потоци. Използвайте тези API PHP, например чрез `wp eval`, за да проверявате машините от командния ред.

Тези API предоставят текущото име на състоянието, статуса на жизнения цикъл, публичното състояние, наличните събития, метаданните на дефиницията, пълната времева линия на преходите и нормализиран пакет с проследяване за интерфейси за отстраняване на грешки. Редовете в списъка с машини включват версията и хеша на дефиницията и ключа за идемпотентност, така че екраните със списъци да показват версията на източника и средата на изпълнение, без да зареждат всяка машина поотделно. Пакетът с проследяване включва групирани състояния, необработени събития, свързани задачи за действия, регистрационни файлове, препратки към артефакти, препратки към фрагменти, входни и изходни данни на обработчика, състоянието преди и след действието, контекст, времена и структурирани грешки.

## Сесии на агенти

Машините на състоянията са особено полезни за агентски системи, които приличат повече на сесии, отколкото на конвейери. Сесия, която преминава през `awaiting_user`, `planning`, `running_agents`, `awaiting_review` и `completed`, обикновено се разбира по-лесно като явен жизнен цикъл, отколкото като една много дълга дефиниция на работен поток с множество изчаквания и обратни връзки.

## Вижте също

- [Neuron Машина на състоянията за сесия](https://queuety.inline0.dev/bg/docs/examples/neuron-session-state-machine)
- [Neuron Машина на състоянията за памет и преглед](https://queuety.inline0.dev/bg/docs/examples/neuron-memory-review)
- [Оркестриране на агенти](https://queuety.inline0.dev/bg/docs/workflows/agent-orchestration)
- [Сигнали на работния поток](https://queuety.inline0.dev/bg/docs/workflows/signals)
- [Зависимости на работния поток](https://queuety.inline0.dev/bg/docs/workflows/dependencies)
- [Повторения](https://queuety.inline0.dev/bg/docs/workflows/repeats)
- [Артефакти](https://queuety.inline0.dev/bg/docs/features/artifacts)
- [PHP API](https://queuety.inline0.dev/bg/docs/api)
