Към съдържанието

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

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

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

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

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(), използващ същите ключове за правила за ресурсите като стъпките и обработчиците на работния поток. Така можете да включите скъп преход на състояние в споделена група за конкурентност или да зададете по-висока тежест на разхода, когато действието използва повече ресурс от обичайна стъпка.

По-широкият модел за ресурси е описан в Управление на ресурсите.

Договори

Действията при влизане в състояние имплементират 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, обикновено се разбира по-лесно като явен жизнен цикъл, отколкото като една много дълга дефиниция на работен поток с множество изчаквания и обратни връзки.

Вижте също