
# Отмена рабочего процесса

Рабочие процессы можно отменять программно или через CLI. При отмене рабочего процесса Queuety устанавливает статус `cancelled`, помещает все ожидающие и выполняющиеся задания в архив и запускает необязательный обработчик очистки.

## Регистрация обработчика очистки

Используйте `on_cancel()` в конструкторе workflow, чтобы зарегистрировать класс, который запускается при отмене workflow. Класс обработчика должен реализовывать метод `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 ] );
```

Обработчик очистки получает публичное состояние workflow (все ключи, не начинающиеся с `_`):

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

## Отмена через PHP

Вызовите `Queuety::cancel_workflow()`, указав ID workflow:

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

Этот метод:

1. Блокирует строку workflow
2. Устанавливает для workflow статус `cancelled`
3. Перемещает все ожидающие и обрабатываемые задания workflow в отложенные с сообщением "Workflow cancelled"
4. Записывает событие `workflow_cancelled` и выполняет фиксацию
5. Запускает компенсацию завершенных шагов в обратном порядке (если она была зарегистрирована через `compensate_with()`)
6. Запускает обработчик очистки `on_cancel` (если он зарегистрирован)

Если workflow уже `completed` или `cancelled`, выбрасывается `RuntimeException`.

## Отмена через CLI

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

| Параметр | Описание |
|---|---|
| `<id>` | ID рабочего процесса для отмены (обязательно) |

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

## Что происходит при отмене

При отмене workflow:

- **Статус** меняется на `cancelled`
- **Компенсации шагов** запускаются в обратном порядке завершения, если вы назначили их с помощью `compensate_with()`
- **Обработчик очистки** запускается после того, как строке workflow присвоен статус `cancelled`
- **Ожидающие задания** workflow немедленно перемещаются в отложенные
- **Обрабатываемые задания** workflow перемещаются в отложенные; когда выполняющийся обработчик завершится, его результат будет отброшен, и workflow не перейдет дальше
- **Завершенные задания** предыдущих шагов остаются без изменений
- **Запись журнала** с событием `workflow_cancelled` сохраняется

## Отмена и сбой

| Аспект | Сбой | Отмена |
|---|---|---|
| Причина | У шага исчерпаны попытки повтора | Явный вызов `cancel_workflow()` |
| Статус | `failed` | `cancelled` |
| Можно повторить | Да, с помощью `retry_workflow()`, если компенсация workflow еще не выполнялась | Нет |
| Обработчик очистки | Не вызывается | Вызывается, если зарегистрирован через `on_cancel()` |
| Событие журнала | `workflow_failed` | `workflow_cancelled` |

## Пример: отмена с подтверждением

Обычно перед отменой проверяют статус workflow:

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