
# Workflow-Abbruch

Workflows können programmatisch oder über CLI abgebrochen werden. Beim Abbruch setzt Queuety den Status auf `cancelled`, legt ausstehende oder laufende Jobs auf Eis und führt einen optionalen Bereinigungshandler aus.

## Bereinigungshandler registrieren

Verwende `on_cancel()` im Workflow-Builder, um eine Klasse zu registrieren, die beim Abbruch des Workflows ausgeführt wird. Die Handler-Klasse muss eine `handle( array $state ): void`-Methode implementieren.

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

Der Bereinigungshandler erhält den öffentlichen Workflow-Zustand (alle Schlüssel, die nicht mit `_` beginnen):

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

## Abbrechen über PHP

Rufe `Queuety::cancel_workflow()` mit der Workflow-ID auf:

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

Diese Methode:

1. Sperrt die Workflow-Zeile
2. Setzt den Workflow-Status auf `cancelled`
3. Legt alle ausstehenden und laufenden Jobs des Workflows mit der Nachricht "Workflow cancelled" auf Eis
4. Protokolliert ein Ereignis vom Typ `workflow_cancelled` und führt einen Commit aus
5. Führt Kompensationen für abgeschlossene Schritte in umgekehrter Reihenfolge aus (sofern über `compensate_with()` registriert)
6. Führt den Bereinigungshandler `on_cancel` aus (sofern registriert)

Eine `RuntimeException` wird ausgelöst, wenn der Workflow bereits `completed` oder `cancelled` ist.

## Abbrechen über CLI

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

| Option | Beschreibung |
|---|---|
| `<id>` | Workflow-ID für den Abbruch (erforderlich) |

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

## Was beim Abbruch geschieht

Beim Abbruch eines Workflows:

- **Status** wechselt zu `cancelled`
- **Schrittkompensationen** werden in umgekehrter Abschlussreihenfolge ausgeführt, wenn du sie mit `compensate_with()` hinzugefügt hast
- **Bereinigungshandler** wird ausgeführt, nachdem die Workflow-Zeile als `cancelled` markiert wurde
- **Ausstehende Jobs** des Workflows werden sofort auf Eis gelegt
- **Laufende Jobs** des Workflows werden auf Eis gelegt; wenn der gerade ausgeführte Handler fertig ist, wird seine Ausgabe verworfen und der Workflow nicht fortgesetzt
- **Abgeschlossene Jobs** aus früheren Schritten bleiben unverändert
- **Ein Protokolleintrag** mit dem Ereignis `workflow_cancelled` wird aufgezeichnet

## Abgebrochen oder fehlgeschlagen

| Aspekt | Fehlgeschlagen | Abgebrochen |
|---|---|---|
| Auslöser | Ein Schritt schöpft seine Wiederholungsversuche aus | Expliziter Aufruf von `cancel_workflow()` |
| Status | `failed` | `cancelled` |
| Wiederholbar | Ja, über `retry_workflow()`, sofern der Workflow nicht bereits kompensiert wurde | Nein |
| Bereinigungshandler | Wird nicht aufgerufen | Wird aufgerufen, sofern über `on_cancel()` registriert |
| Protokollereignis | `workflow_failed` | `workflow_cancelled` |

## Beispiel: Abbruch mit Bestätigung

Ein gängiges Muster ist, den Workflow-Status vor dem Abbruch zu prüfen:

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