
# Предпазни мерки за работните потоци

Работните потоци от агентен тип са гъвкави, но също така улесняват създаването на дублирани изпълнения или генерирането на повече работа от предвиденото от планиращата стъпка. Queuety предоставя леки предпазни мерки на ниво работен поток, за да запазите тази гъвкавост, без да губите контрол.

За по-широкия модел на ресурси за допускане на работници и метаданни за разходите по задача вижте [Управление на ресурсите](https://queuety.inline0.dev/bg/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 връща първоначалния идентификатор на работния поток, вместо да създава дублирано изпълнение. Ключовете са глобални за всички имена на работни потоци, затова включете името на работния поток в ключа, ако различни работни потоци могат да използват един и същ ключ.

Това е особено полезно за:

- крайни точки 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`.

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