
# Обмеження процесів

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

Докладніше про загальну модель ресурсів, допуск виконавців і метадані вартості окремих завдань див. у розділі [Керування ресурсами](https://queuety.inline0.dev/uk/docs/features/resource-management).

## Версіонування визначення процесу

Використовуйте `version()`, щоб додати мітку версії рівня застосунку до визначення процесу:

```php
Queuety::workflow( 'research_run' )
    ->version( 'research.v2' )
    ->then( PlanResearchStep::class )
    ->then( DraftResearchSummaryStep::class )
    ->dispatch();
```

Версія зберігається разом зі станом процесу, доступна через `workflow_status()`, виводиться командою `wp queuety workflow status` і включається до експорту процесу.

Queuety також зберігає детермінований `definition_hash` для кожного запуску процесу. Хеш обчислюється на основі серіалізованого визначення процесу й допомагає точно встановити, який процес виконується під час розгортання для запуску, що ще триває.

## Забезпечення ідемпотентності запуску

Використовуйте `idempotency_key()`, якщо викликачі можуть повторно надсилати той самий запит:

```php
Queuety::workflow( 'research_run' )
    ->idempotency_key( 'brief:42:research' )
    ->then( PlanResearchStep::class )
    ->dispatch( [ 'brief_id' => 42 ] );
```

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

Це особливо корисно для:

- кінцевих точок API, запити до яких можуть повторно надсилати клієнти або шлюзи
- обробників вебхуків, які можуть отримувати дублікати доставлень
- кроків планування, що мають створювати лише один запуск оркестрації для кожної зовнішньої сутності

Ключі ідемпотентності зберігаються в таблиці `queuety_workflow_dispatch_keys`.

## Встановлення бюджетів процесу

Використовуйте бюджети процесу, щоб зупиняти запуски, які виходять за заплановані межі:

```php
Queuety::workflow( 'research_run' )
    ->max_transitions( 20 )
    ->max_for_each_items( 12 )
    ->max_state_bytes( 32768 )
    ->max_cost_units( 40 )
    ->max_started_workflows( 8 )
    ->then( PlanResearchStep::class )
    ->for_each( 'tasks', ExecuteResearchTask::class, 'results' )
    ->dispatch();
```

### `max_transitions()`

Обмежує кількість кроків процесу, які можуть завершитися до того, як запуск завершиться помилкою. Це корисно для захисту процесів із динамічним розгалуженням або можливістю повертатися до тієї самої ділянки через `_next_step`.

### `max_for_each_items()`

Обмежує кількість елементів, виявлених під час виконання, на які може розгорнутися один крок `for_each()`. Це корисно для систем планування та виконання, у яких агент може виявити набагато більше роботи для гілок, ніж очікувалося.

### `max_state_bytes()`

Обмежує закодований розмір публічного стану процесу. Це не дає довготривалим процесам розростатися до великих об'єктів, які повільно перевіряти, експортувати чи повторно запускати.

### `max_cost_units()`

Обмежує загальну кількість одиниць вартості, використаних завершеними кроками. Одиниці вартості беруться з метаданих кроку або завдання, які Queuety визначає під час додавання роботи в чергу. Для звичайної роботи користувача за замовчуванням використовується `1`, для службових елементів оркестрації, як-от затримок і очікувань, — `0`. Обробники можуть задати більше додатне значення через `config()` або властивості завдання. Лише `cost_units` у визначенні кроку може задати значення `0`.

Це корисно, якщо процес може повертатися до тієї самої ділянки або цикл for-each обробляє роботу, витрати на яку не відображаються лише кількістю кроків. Планувальник, який постійно повторно викликає дорогу модель, може не перевищити `max_transitions()`, але все одно вийти за запланований бюджет витрат.

### `max_started_workflows()`

Обмежує кількість процесів верхнього рівня, які запуск може створити через `start_workflows()` або `start_agents()`. Ліміт перевіряється до запуску дочірніх процесів, тож батьківський процес завершується помилкою, не створюючи часткову групу, що вже перевищує бюджет.

Якщо бюджет перевищено, Queuety негайно завершує робочий процес замість повторної спроби виконати крок. Є один виняток: якщо `Queuety::signal()` завершує очікування, а отриманий перехід перевищує бюджет, виняток передається виклику `signal()`, вставлення сигналу відкочується, а робочий процес продовжує очікування.

## Спостереження за обмеженнями

Статус робочого процесу містить:

- `definition_version`
- `definition_hash`
- `idempotency_key`
- `budget`

Дані `budget` містять налаштовані обмеження та поточне використання, зокрема поточний розмір публічного стану в байтах.

Приклад:

```php
$state = Queuety::workflow_status( $workflow_id );

$state->definition_version; // 'research.v2'
$state->definition_hash;    // '4c7a...'
$state->idempotency_key;    // 'brief:42:research'
$state->budget;             // [ 'max_transitions' => 20, ... ]
```
