Робочі процеси
Робочі процеси розбивають тривалу роботу на окремі кроки. Результат кожного кроку зберігається в спільному сховищі стану в базі даних. Якщо PHP завершує роботу посеред кроку, виконавець повторює цей крок, зберігаючи весь попередній стан.
Що таке робочі процеси?
Робочий процес — це впорядкована послідовність кроків. Кожен крок — це клас PHP, який отримує накопичений стан усіх попередніх кроків і повертає нові дані для об’єднання зі станом. Робочий процес просувається по одному кроку за раз, а кожен перехід виконується в атомарній транзакції MySQL.
use Queuety\Queuety;
$workflow_id = Queuety::workflow( 'generate_report' )
->then( FetchDataHandler::class )
->then( CallLLMHandler::class )
->then( FormatOutputHandler::class )
->dispatch( [ 'user_id' => 42 ] );
Накопичення стану
Початкові дані, передані в dispatch(), стають початковим станом. Ключі, повернуті кожним кроком, об’єднуються зі станом. Ключі, що починаються з _, зарезервовані для керувальних значень, як-от _next_step, і не об’єднуються з публічним станом:
dispatch(['user_id' => 42])
Step 0: FetchDataHandler -> returns ['user_name' => 'Alice']
state: {user_id: 42, user_name: 'Alice'}
Step 1: CallLLMHandler -> returns ['llm_response' => '...']
state: {user_id: 42, user_name: 'Alice', llm_response: '...'}
Step 2: FormatOutputHandler -> returns ['report_url' => '/reports/42.pdf']
state: {user_id: 42, user_name: 'Alice', llm_response: '...', report_url: '/reports/42.pdf'}
Кожен крок отримує весь накопичений стан. Завдяки цьому можна легко передавати дані між кроками без зовнішнього сховища.
Можливість відновлення
Робочі процеси надійні, оскільки стан зберігається в базі даних після кожного кроку. Якщо виконавець аварійно завершує роботу під час кроку 1, робочий процес запускається знову з кроку 1, а результат кроку 0 вже міститься в стані.
Межа кроку — це одна транзакція MySQL, яка атомарно:
- Оновлює стан робочого процесу результатом кроку
- Позначає завдання поточного кроку як виконане
- Ставить у чергу завдання наступного кроку
Це гарантує, що стан ніколи не буде втрачено, навіть у разі аварій, перевищення часу очікування або фатальних помилок PHP.
Життєвий цикл робочого процесу
dispatch() -> running -> step 0 -> step 1 -> ... -> step N -> completed
| |
| +-> failed -> retry -> running (from failed step)
|
+-> paused -> resumed -> running
|
+-> waiting_for_signal -> signal received -> running
|
+-> waiting_for_workflows -> dependency settles -> running
|
+-> cancelled (via cancel_workflow)
| Статус | Опис |
|---|---|
running |
Активно виконує кроки |
completed |
Усі кроки успішно завершено |
failed |
Крок завершився помилкою після вичерпання повторних спроб |
paused |
Призупинено вручну. Поточна робота може завершитися, але наступні кроки не ставляться в чергу до відновлення |
waiting_for_signal |
Очікує зовнішній сигнал через Queuety::signal() |
waiting_for_workflows |
Очікує завершення одного або кількох інших робочих процесів через wait_for_workflow() або wait_for_workflows() |
cancelled |
Явно скасовано через Queuety::cancel_workflow(). Очікувані завдання приховуються, а необов’язковий обробник очищення виконується. |
Керування робочими процесами
Перевірка статусу:
$state = Queuety::workflow_status( $workflow_id );
echo $state->status->value; // 'running'
echo $state->current_step; // 1
echo $state->total_steps; // 3
print_r( $state->waiting_for ); // ['42'] while waiting on another workflow
print_r( $state->wait_details ); // matched/remaining blockers, result key, correlation info
Призупинення та відновлення:
Queuety::pause_workflow( $workflow_id );
Queuety::resume_workflow( $workflow_id );
Повторний запуск робочого процесу з помилкою, починаючи з кроку, що завершився помилкою:
Queuety::retry_workflow( $workflow_id );
Скасування робочого процесу та запуск обробників очищення:
Queuety::cancel_workflow( $workflow_id );
Докладніше про обробники очищення та наслідки скасування робочого процесу див. в розділі Скасування.
Параметри робочого процесу
Налаштуйте чергу, пріоритет і поведінку повторних спроб для всіх кроків робочого процесу:
use Queuety\Enums\Priority;
Queuety::workflow( 'important_pipeline' )
->on_queue( 'pipelines' )
->with_priority( Priority::High )
->max_attempts( 5 )
->on_cancel( PipelineCleanupHandler::class )
->prune_state_after( 3 )
->then( StepA::class )
->then( StepB::class )
->dispatch( $payload );
Метод on_cancel() реєструє обробник очищення, який запускається під час скасування робочого процесу. Див. розділ Скасування.
Метод prune_state_after() вмикає автоматичне видалення старих результатів кроків, щоб обмежити розмір стану робочого процесу. Див. розділ Очищення стану.
Використовуйте compensate_with(), щоб додати обробник компенсації для окремого кроку. Використовуйте compensate_on_failure(), щоб автоматично виконувати компенсацію завершених кроків після збою робочого процесу, а не лише в разі явного скасування. Див. розділ Компенсація.
Використовуйте обмеження робочого процесу для безпечнішої тривалої оркестрації: version() додає до визначення тег із версією на рівні застосунку, Queuety також зберігає детермінований хеш визначення для кожного запуску, idempotency_key() забезпечує надійну диспетчеризацію під час повторних спроб або дублікатів запитів, а max_transitions(), max_for_each_items() і max_state_bytes() зупиняють неконтрольовані запуски до того, як ситуація вийде з-під контролю. Див. розділ Обмеження.
Типи кроків
Queuety підтримує одинадцять типів кроків у робочому процесі:
- Послідовні ланцюжки за допомогою
->then()для послідовного виконання - Паралельні групи за допомогою
->parallel()для паралельного виконання - Динамічний цикл для кожного елемента за допомогою
->for_each()для роботи з гілками, виявленими під час виконання, та явної семантики завершення - Асинхронна передача за допомогою
->start_workflows()або->start_agents()для запуску незалежних дочірніх робочих процесів для елементів, виявлених під час виконання - Умовне розгалуження за допомогою іменованих кроків і
_next_step - Повтори за допомогою
->repeat_until()і->repeat_while()для надійного повернення до попередніх іменованих кроків - Запуск робочих процесів за допомогою
->run_workflow()для вкладеної композиції - Надійні затримки за допомогою
->delay()для затримок на заданий час - Сигнали за допомогою
->wait_for_signal(),->wait_for_signals(),->wait_for_approval(),->wait_for_input()і->wait_for_decision()для запуску зовнішніми подіями - Залежності робочих процесів за допомогою
->wait_for_workflow(),->wait_for_workflows()і->wait_for_agents()для координації між робочими процесами - Потокові кроки за допомогою інтерфейсу
StreamingStepдля надійного виведення порціями
Типові сценарії
Якщо ви створюєте автономні або напівавтономні системи, почніть із розділу Оркестрація агентів. У ньому показано, як for_each(), start_agents(), wait_for_agents(), wait_for_workflow() і wait_for_decision() працюють разом у реальних сценаріях із планувальником, виконавцем і перевіркою людиною.