
# Скасування робочого процесу

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

## Реєстрація обробника очищення

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

Обробник очищення отримує публічний стан робочого процесу (усі ключі, що не починаються з `_`):

```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()` з ідентифікатором робочого процесу:

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

Цей метод:

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

Якщо робочий процес уже має статус `completed` або `cancelled`, буде викинуто `RuntimeException`.

## Скасування через CLI

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

| Опція | Опис |
|---|---|
| `<id>` | ID робочого процесу для скасування (обов’язково) |

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

## Що відбувається під час скасування

Коли робочий процес скасовано:

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

## Скасування та помилка

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

## Приклад: скасування з підтвердженням

Поширений шаблон — перевірити статус робочого процесу перед скасуванням:

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