
# Робочі процеси

Робочі процеси розбивають тривалу роботу на окремі кроки. Результат кожного кроку зберігається в спільному сховищі стану в базі даних. Якщо PHP завершує роботу посеред кроку, виконавець повторює цей крок, зберігаючи весь попередній стан.

## Що таке робочі процеси?

Робочий процес — це впорядкована послідовність кроків. Кожен крок — це клас PHP, який отримує накопичений стан усіх попередніх кроків і повертає нові дані для об’єднання зі станом. Робочий процес просувається по одному кроку за раз, а кожен перехід виконується в атомарній транзакції MySQL.

```php
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, яка атомарно:
1. Оновлює стан робочого процесу результатом кроку
2. Позначає завдання поточного кроку як виконане
3. Ставить у чергу завдання наступного кроку

Це гарантує, що стан ніколи не буде втрачено, навіть у разі аварій, перевищення часу очікування або фатальних помилок 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()`. Очікувані завдання приховуються, а необов’язковий обробник очищення виконується. |

## Керування робочими процесами

Перевірка статусу:

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

Призупинення та відновлення:

```php
Queuety::pause_workflow( $workflow_id );
Queuety::resume_workflow( $workflow_id );
```

Повторний запуск робочого процесу з помилкою, починаючи з кроку, що завершився помилкою:

```php
Queuety::retry_workflow( $workflow_id );
```

Скасування робочого процесу та запуск обробників очищення:

```php
Queuety::cancel_workflow( $workflow_id );
```

Докладніше про обробники очищення та наслідки скасування робочого процесу див. в розділі [Скасування](https://queuety.inline0.dev/uk/docs/workflows/cancellation).

## Параметри робочого процесу

Налаштуйте чергу, пріоритет і поведінку повторних спроб для всіх кроків робочого процесу:

```php
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()` реєструє обробник очищення, який запускається під час скасування робочого процесу. Див. розділ [Скасування](https://queuety.inline0.dev/uk/docs/workflows/cancellation).

Метод `prune_state_after()` вмикає автоматичне видалення старих результатів кроків, щоб обмежити розмір стану робочого процесу. Див. розділ [Очищення стану](https://queuety.inline0.dev/uk/docs/features/state-pruning).

Використовуйте `compensate_with()`, щоб додати обробник компенсації для окремого кроку. Використовуйте `compensate_on_failure()`, щоб автоматично виконувати компенсацію завершених кроків після збою робочого процесу, а не лише в разі явного скасування. Див. розділ [Компенсація](https://queuety.inline0.dev/uk/docs/workflows/compensation).

Використовуйте обмеження робочого процесу для безпечнішої тривалої оркестрації: `version()` додає до визначення тег із версією на рівні застосунку, Queuety також зберігає детермінований хеш визначення для кожного запуску, `idempotency_key()` забезпечує надійну диспетчеризацію під час повторних спроб або дублікатів запитів, а `max_transitions()`, `max_for_each_items()` і `max_state_bytes()` зупиняють неконтрольовані запуски до того, як ситуація вийде з-під контролю. Див. розділ [Обмеження](https://queuety.inline0.dev/uk/docs/workflows/guardrails).

## Типи кроків

Queuety підтримує одинадцять типів кроків у робочому процесі:

- [Послідовні ланцюжки](https://queuety.inline0.dev/uk/docs/workflows/chains) за допомогою `->then()` для послідовного виконання
- [Паралельні групи](https://queuety.inline0.dev/uk/docs/workflows/parallel) за допомогою `->parallel()` для паралельного виконання
- [Динамічний цикл для кожного елемента](https://queuety.inline0.dev/uk/docs/workflows/for-each) за допомогою `->for_each()` для роботи з гілками, виявленими під час виконання, та явної семантики завершення
- [Асинхронна передача](https://queuety.inline0.dev/uk/docs/workflows/async-handoffs) за допомогою `->start_workflows()` або `->start_agents()` для запуску незалежних дочірніх робочих процесів для елементів, виявлених під час виконання
- [Умовне розгалуження](https://queuety.inline0.dev/uk/docs/workflows/conditional) за допомогою іменованих кроків і `_next_step`
- [Повтори](https://queuety.inline0.dev/uk/docs/workflows/repeats) за допомогою `->repeat_until()` і `->repeat_while()` для надійного повернення до попередніх іменованих кроків
- [Запуск робочих процесів](https://queuety.inline0.dev/uk/docs/workflows/run-workflows) за допомогою `->run_workflow()` для вкладеної композиції
- [Надійні затримки](https://queuety.inline0.dev/uk/docs/workflows/delays) за допомогою `->delay()` для затримок на заданий час
- [Сигнали](https://queuety.inline0.dev/uk/docs/workflows/signals) за допомогою `->wait_for_signal()`, `->wait_for_signals()`, `->wait_for_approval()`, `->wait_for_input()` і `->wait_for_decision()` для запуску зовнішніми подіями
- [Залежності робочих процесів](https://queuety.inline0.dev/uk/docs/workflows/dependencies) за допомогою `->wait_for_workflow()`, `->wait_for_workflows()` і `->wait_for_agents()` для координації між робочими процесами
- [Потокові кроки](https://queuety.inline0.dev/uk/docs/workflows/streaming) за допомогою інтерфейсу `StreamingStep` для надійного виведення порціями

## Типові сценарії

Якщо ви створюєте автономні або напівавтономні системи, почніть із розділу [Оркестрація агентів](https://queuety.inline0.dev/uk/docs/workflows/agent-orchestration). У ньому показано, як `for_each()`, `start_agents()`, `wait_for_agents()`, `wait_for_workflow()` і `wait_for_decision()` працюють разом у реальних сценаріях із планувальником, виконавцем і перевіркою людиною.
