
# Misure di protezione dei flussi di lavoro

I flussi di lavoro in stile agent sono flessibili, ma facilitano anche la creazione di esecuzioni duplicate o la generazione di più lavoro del previsto da parte di un planner. Queuety offre misure di protezione leggere a livello di flusso di lavoro, così potete mantenere questa flessibilità senza perdere il controllo.

Per una panoramica più ampia delle risorse per l'ammissione dei worker e dei metadati dei costi per job, consultate [Gestione delle risorse](https://queuety.inline0.dev/it/docs/features/resource-management).

## Assegnare una versione alla definizione del flusso di lavoro

Usate `version()` per associare un'etichetta di versione a livello applicativo alla definizione di un flusso di lavoro:

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

La versione viene salvata con lo stato del flusso di lavoro, resa disponibile tramite `workflow_status()`, stampata da `wp queuety workflow status` e inclusa nelle esportazioni del flusso di lavoro.

Queuety salva anche un `definition_hash` deterministico per ogni esecuzione del flusso di lavoro. L'hash deriva dalla definizione serializzata del flusso di lavoro ed è utile quando, dopo un deploy, dovete identificare con precisione la struttura eseguita da un'esecuzione ancora in corso.

## Rendere idempotente il dispatch

Usate `idempotency_key()` quando i chiamanti potrebbero ripetere la stessa richiesta:

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

Se il dispatch di un flusso di lavoro viene ripetuto con una chiave già usata, Queuety restituisce l'ID del flusso di lavoro originale invece di creare un'esecuzione duplicata. Le chiavi sono globali per tutti i nomi dei flussi di lavoro, quindi includete il nome del flusso nella chiave quando flussi diversi potrebbero condividerne una.

È particolarmente utile per:

- endpoint API che i client o i gateway potrebbero richiamare di nuovo
- consumer di webhook che possono ricevere consegne duplicate
- passaggi planner che dovrebbero creare una sola esecuzione di orchestrazione per entità esterna

Le chiavi di idempotenza vengono salvate nella tabella `queuety_workflow_dispatch_keys`.

## Impostare i limiti dei flussi di lavoro

Usate i limiti dei flussi di lavoro per interrompere le esecuzioni che superano l'inviluppo previsto:

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

Limita il numero di passaggi del flusso di lavoro che possono essere completati prima che l'esecuzione non riesca. È utile per proteggere i flussi di lavoro con ramificazioni dinamiche o che possono tornare alla stessa area tramite `_next_step`.

### `max_for_each_items()`

Limita quanti elementi individuati durante l'esecuzione può espandere un singolo passaggio `for_each()`. È utile per i sistemi planner/executor, in cui un agent potrebbe individuare molti più rami di lavoro del previsto.

### `max_state_bytes()`

Limita le dimensioni codificate dello stato pubblico del flusso di lavoro. Aiuta a evitare che i flussi di lavoro di lunga durata diventino blocchi di grandi dimensioni, lenti da ispezionare, esportare o ritentare.

### `max_cost_units()`

Limita le unità di costo totali consumate dai passaggi completati. Le unità di costo derivano dai metadati del passaggio o del job che Queuety risolve quando inserisce il lavoro in coda. Il lavoro utente normale usa per impostazione predefinita `1`; i segnaposto di orchestrazione, come ritardi e attese, usano `0`; i gestori possono impostare un valore positivo superiore tramite `config()` o le proprietà del job. Solo `cost_units` della definizione del passaggio può impostare un valore pari a `0`.

È utile quando un flusso di lavoro può tornare alla stessa area o ripetere un lavoro che ha costi non rilevati dal solo conteggio dei passaggi. Un planner che continua a ripetere una costosa chiamata a un modello potrebbe rispettare `max_transitions()` ma superare comunque il limite di costo previsto.

### `max_started_workflows()`

Limita il numero di flussi di lavoro di primo livello che un'esecuzione può avviare tramite `start_workflows()` o `start_agents()`. Il limite viene verificato prima che i flussi di lavoro secondari vengano avviati, così l'esecuzione principale non riesce senza creare parzialmente un gruppo che superi già il limite.

Quando si supera un limite, Queuety interrompe subito il flusso di lavoro invece di riprovare il passaggio. Un'eccezione: quando `Queuety::signal()` completa un'attesa e la transizione risultante supera un limite, l'eccezione viene propagata al chiamante di `signal()`, l'inserimento del segnale viene annullato e il flusso di lavoro continua ad attendere.

## Monitoraggio delle protezioni

Lo stato del flusso di lavoro espone:

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

Il payload di `budget` include i limiti configurati e l'utilizzo attuale, comprese le dimensioni in byte dello stato pubblico attuale.

Esempio:

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