
# Annullamento dei workflow

I workflow possono essere annullati a livello di codice o tramite CLI. Quando un workflow viene annullato, Queuety imposta il suo stato su `cancelled`, mette in archivio tutti i job in attesa o in elaborazione ed esegue un handler di pulizia facoltativo.

## Registrazione di un gestore di pulizia

Usate `on_cancel()` nel generatore del workflow per registrare una classe che viene eseguita quando il workflow viene annullato. La classe del gestore deve implementare un metodo `handle( array $state ): void`.

```php
use Queuety\Queuety;

Queuety::workflow( 'import_data' )
    ->then( FetchDataHandler::class )
    ->then( TransformDataHandler::class )
    ->then( LoadDataHandler::class )
    ->on_cancel( ImportCleanupHandler::class )
    ->dispatch( [ 'source_url' => $url ] );
```

Il gestore di pulizia riceve lo stato pubblico del workflow (tutte le chiavi che non iniziano con `_`):

```php
class ImportCleanupHandler {

    public function handle( array $state ): void {
        // Clean up any partial imports.
        if ( isset( $state['temp_table'] ) ) {
            global $wpdb;
            $wpdb->query( "DROP TABLE IF EXISTS {$state['temp_table']}" );
        }

        // Notify the user.
        wp_mail(
            $state['notify_email'] ?? '',
            'Import cancelled',
            'Your data import was cancelled.'
        );
    }
}
```

## Annullamento tramite PHP

Chiamate `Queuety::cancel_workflow()` con l'ID del workflow:

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

Questo metodo:

1. Blocca la riga del workflow
2. Imposta lo stato del workflow su `cancelled`
3. Seppellisce tutti i job in sospeso e in elaborazione del workflow con il messaggio "Workflow cancelled"
4. Registra un evento `workflow_cancelled` e conferma la transazione
5. Esegue le compensazioni dei passaggi completati in ordine inverso (se ne sono state registrate tramite `compensate_with()`)
6. Esegue il gestore di pulizia `on_cancel` (se registrato)

Viene lanciato un `RuntimeException` se il workflow è già `completed` o `cancelled`.

## Annullamento tramite CLI

```bash
wp queuety workflow cancel <id>
```

| Opzione | Descrizione |
|---|---|
| `<id>` | ID del workflow da annullare (obbligatorio) |

```bash
wp queuety workflow cancel 42
```

## Cosa accade quando si annulla

Quando un workflow viene annullato:

- **Stato** passa a `cancelled`
- Le **compensazioni dei passaggi** vengono eseguite in ordine inverso di completamento, se le avete associate con `compensate_with()`
- Il **gestore di pulizia** viene eseguito dopo che la riga del workflow è stata contrassegnata come `cancelled`
- I **job in sospeso** del workflow vengono seppelliti immediatamente
- I **job in elaborazione** del workflow vengono seppelliti; al termine del gestore in corso, il suo output viene scartato e il workflow non avanza
- I **job completati** dei passaggi precedenti rimangono invariati
- Viene registrata una **voce di log** con l'evento `workflow_cancelled`

## Annullato o non riuscito

| Aspetto | Non riuscito | Annullato |
|---|---|---|
| Attivazione | Un passaggio esaurisce i tentativi di ripetizione | Chiamata esplicita a `cancel_workflow()` |
| Stato | `failed` | `cancelled` |
| Possibilità di riprovare | Sì, tramite `retry_workflow()`, a meno che il workflow non sia già stato compensato | No |
| Gestore di pulizia | Non viene chiamato | Viene chiamato se registrato tramite `on_cancel()` |
| Evento di log | `workflow_failed` | `workflow_cancelled` |

## Esempio: annullamento con conferma

Un modello comune consiste nel controllare lo stato del workflow prima di annullarlo:

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

if ( null === $status ) {
    throw new \RuntimeException( 'Workflow not found.' );
}

if ( 'running' === $status->status->value || 'paused' === $status->status->value ) {
    Queuety::cancel_workflow( $workflow_id );
}
```
