
# Отмяна на работен поток

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

## Регистриране на обработчик за почистване

Използвайте `on_cancel()` в конструкторa на работния поток, за да регистрирате клас, който се изпълнява при отмяна на работния поток. Класът на обработчика трябва да реализира метод `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()` с ID на работния поток:

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

Този метод:

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

Ако работният поток вече е `completed` или `cancelled`, се хвърля `RuntimeException`.

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

```bash
wp queuety workflow cancel <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 );
}
```
