
# Zabezpieczenia przepływu pracy

Przepływy pracy w stylu agentowym są elastyczne, ale łatwiej w nich też tworzyć zduplikowane uruchomienia lub pozwolić planiście wygenerować więcej pracy, niż zamierzono. Queuety zapewnia lekkie zabezpieczenia na poziomie przepływu pracy, dzięki którym możesz zachować elastyczność bez utraty kontroli.

Więcej informacji o szerszym modelu zasobów, obejmującym dopuszczanie zadań pracowników i metadane kosztów poszczególnych zadań, znajdziesz w sekcji [Zarządzanie zasobami](https://queuety.inline0.dev/pl/docs/features/resource-management).

## Wersjonowanie definicji przepływu pracy

Użyj `version()`, aby dodać do definicji przepływu pracy etykietę wersji na poziomie aplikacji:

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

Wersja jest przechowywana wraz ze stanem przepływu pracy, udostępniana przez `workflow_status()`, wyświetlana przez `wp queuety workflow status` i dołączana do eksportów przepływu pracy.

Queuety przechowuje też deterministyczny `definition_hash` dla każdego uruchomienia przepływu pracy. Skrót jest wyliczany na podstawie zserializowanej definicji i pomaga dokładnie określić, jaki kształt przepływu wykonuje uruchomienie będące w toku po wdrożeniu.

## Idempotentne przekazywanie

Użyj `idempotency_key()`, gdy wywołujący mogą ponawiać to samo żądanie:

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

Jeśli przepływ pracy zostanie ponownie uruchomiony z kluczem, który był już użyty, Queuety zwróci oryginalny identyfikator przepływu zamiast tworzyć zduplikowane uruchomienie. Klucze są globalne dla wszystkich nazw przepływów pracy, więc jeśli różne przepływy mogą używać tego samego klucza, uwzględnij w nim nazwę przepływu.

Przydaje się to szczególnie w przypadku:

- punktów końcowych API, których wywołania mogą być ponawiane przez klientów lub bramy
- odbiorców webhooków, którzy mogą otrzymać zduplikowane dostarczenia
- kroków planisty, które powinny utworzyć tylko jedno uruchomienie orkiestracji dla każdego zewnętrznego obiektu

Klucze idempotencji są przechowywane w tabeli `queuety_workflow_dispatch_keys`.

## Ustawianie limitów przepływu pracy

Skonfiguruj limity przepływu pracy, aby przerywać uruchomienia przekraczające zaplanowane wartości:

```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()`

Ogranicza liczbę kroków przepływu pracy, które mogą się zakończyć, zanim uruchomienie zostanie przerwane. Przydaje się to do ochrony przepływów pracy z dynamicznymi odgałęzieniami lub wielokrotnym powracaniem do tego samego miejsca za pomocą `_next_step`.

### `max_for_each_items()`

Ogranicza liczbę elementów wykrytych w czasie działania, które może rozwinąć pojedynczy krok `for_each()`. Przydaje się to w systemach planista/wykonawca, w których agent może wykryć znacznie więcej pracy w gałęziach, niż zamierzono.

### `max_state_bytes()`

Ogranicza zakodowany rozmiar publicznego stanu przepływu pracy. Dzięki temu stan długo działających przepływów nie rozrasta się do dużych obiektów, które trudno sprawdzać, eksportować lub ponawiać.

### `max_cost_units()`

Ogranicza łączną liczbę jednostek kosztu zużywanych przez ukończone kroki. Jednostki kosztu pochodzą z metadanych kroku lub zadania, które Queuety odczytuje podczas dodawania pracy do kolejki. Zwykła praca użytkownika ma domyślnie wartość `1`, elementy orkiestracji, takie jak opóźnienia i oczekiwanie, mają wartość `0`, a procedury obsługi mogą ustawić wyższą wartość dodatnią przez `config()` lub właściwości zadania. Tylko definicja kroku może ustawić wartość `cost_units` na `0`.

Przydaje się to, gdy przepływ pracy może powracać do tego samego miejsca lub gdy praca w for-each jest kosztowna w sposób niewidoczny w samej liczbie kroków. Planista, który wielokrotnie uruchamia kosztowne wywołanie modelu, może zmieścić się w limicie `max_transitions()`, a mimo to przekroczyć założony budżet kosztów.

### `max_started_workflows()`

Ogranicza liczbę przepływów pracy najwyższego poziomu, które uruchomienie może rozpocząć przez `start_workflows()` lub `start_agents()`. Limit jest sprawdzany przed przekazaniem zadań podrzędnym przepływom, więc nadrzędny przepływ kończy się niepowodzeniem, zanim utworzy grupę przekraczającą limit.

Po przekroczeniu limitu Queuety natychmiast przerywa przepływ pracy zamiast ponawiać próbę kroku. Wyjątek: gdy `Queuety::signal()` kończy oczekiwanie, a wynikające z tego przejście przekracza limit, wyjątek jest przekazywany do wywołującego `signal()`, wstawienie sygnału zostaje wycofane, a przepływ pracy nadal czeka.

## Monitorowanie zabezpieczeń

Status przepływu pracy udostępnia:

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

Ładunek `budget` zawiera skonfigurowane limity i bieżące zużycie, w tym bieżący rozmiar publicznego stanu w bajtach.

Przykład:

```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, ... ]
```
