
# Cancelamento de workflows

Workflows podem ser cancelados programaticamente ou por meio de CLI. Quando um workflow é cancelado, Queuety define seu status como `cancelled`, enterra quaisquer jobs pendentes ou em processamento e executa um handler de limpeza opcional.

## Registrando um handler de limpeza

Use `on_cancel()` no construtor do workflow para registrar uma classe executada quando o workflow for cancelado. A classe do handler deve implementar um método `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 ] );
```

O handler de limpeza recebe o estado público do workflow (todas as chaves que não começam com `_`):

```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.'
        );
    }
}
```

## Cancelamento via PHP

Chame `Queuety::cancel_workflow()` com o ID do workflow:

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

Este método:

1. Bloqueia a linha do workflow
2. Define o status do workflow como `cancelled`
3. Enterra todos os jobs pendentes e em processamento do workflow com a mensagem "Workflow cancelled"
4. Registra um evento `workflow_cancelled` e confirma a transação
5. Executa as compensações das etapas concluídas em ordem inversa (se alguma foi registrada via `compensate_with()`)
6. Executa o handler de limpeza `on_cancel` (se registrado)

Uma `RuntimeException` é lançada se o workflow já estiver `completed` ou `cancelled`.

## Cancelamento via CLI

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

| Opção | Descrição |
|---|---|
| `<id>` | ID do fluxo de trabalho a cancelar (obrigatório) |

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

## O que acontece ao cancelar

Quando um workflow é cancelado:

- **Status** muda para `cancelled`
- **Compensações de etapas** são executadas na ordem inversa de conclusão se você as associou com `compensate_with()`
- **Handler de limpeza** é executado depois que a linha do workflow é marcada como `cancelled`
- **Jobs pendentes** do workflow são enterrados imediatamente
- **Jobs em processamento** do workflow são enterrados; quando o handler em execução termina, sua saída é descartada e o workflow não avança
- **Jobs concluídos** de etapas anteriores permanecem como estão
- **Uma entrada de log** com o evento `workflow_cancelled` é registrada

## Cancelado vs. com falha

| Aspecto | Com falha | Cancelado |
|---|---|---|
| Gatilho | Uma etapa esgota as tentativas de repetição | Chamada explícita a `cancel_workflow()` |
| Status | `failed` | `cancelled` |
| Pode repetir | Sim, via `retry_workflow()`, a menos que o workflow já tenha sido compensado | Não |
| Handler de limpeza | Não é chamado | Chamado se registrado via `on_cancel()` |
| Evento de log | `workflow_failed` | `workflow_cancelled` |

## Exemplo: cancelamento com confirmação

Um padrão comum é verificar o status do workflow antes de cancelá-lo:

```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 );
}
```
