
# Workflow-Kompensation

Mit einer Kompensation kannst du einem abgeschlossenen Workflow-Schritt einen Rollback-Handler hinzufügen. Queuety speichert nach Abschluss des Schritts eine Momentaufnahme des öffentlichen Zustands und führt anschließend die Kompensationshandler in umgekehrter Reihenfolge aus, wenn der Workflow abgebrochen wird oder optional fehlschlägt.

## Die Methode `compensate_with()`

Rufe `compensate_with()` direkt nach dem Schritt auf, den sie rückgängig machen soll:

```php
use Queuety\Queuety;

Queuety::workflow( 'provision_account' )
    ->then( CreateRemoteUserStep::class )
    ->compensate_with( DeleteRemoteUserCompensation::class )
    ->then( CreateSubscriptionStep::class )
    ->compensate_with( CancelSubscriptionCompensation::class )
    ->then( SendWelcomeEmailStep::class )
    ->dispatch( [ 'user_id' => 42 ] );
```

Wird der Workflow später abgebrochen, wird Queuety ausgeführt:

1. `CancelSubscriptionCompensation`
2. `DeleteRemoteUserCompensation`

## Kompensationshandler

Kompensationshandler implementieren `Contracts\Compensation`:

```php
use Queuety\Contracts\Compensation;

final class DeleteRemoteUserCompensation implements Compensation {
    public function handle( array $state ): void {
        remote_api_delete_user( $state['remote_user_id'] );
    }
}
```

Der Handler erhält den öffentlichen Workflow-Zustand, wie er unmittelbar nach Abschluss des kompensierten Schritts aussah. Reservierte interne Schlüssel sind nicht enthalten.

## Abbruch oder Fehler

Bei einem ausdrücklichen Abbruch werden die Kompensationen abgeschlossener Schritte immer vor dem optionalen Handler `on_cancel()` ausgeführt.

Bei einem Fehler werden Kompensationen nur ausgeführt, wenn du sie aktivierst:

```php
Queuety::workflow( 'provision_account' )
    ->then( CreateRemoteUserStep::class )
    ->compensate_with( DeleteRemoteUserCompensation::class )
    ->then( CreateSubscriptionStep::class )
    ->compensate_with( CancelSubscriptionCompensation::class )
    ->then( ChargeCardStep::class )
    ->compensate_on_failure()
    ->dispatch( $payload );
```

Ohne `compensate_on_failure()` behält ein fehlgeschlagener Workflow seinen Verlauf abgeschlossener Schritte bei und kann ab dem fehlgeschlagenen Schritt erneut ausgeführt werden.

Mit `compensate_on_failure()` werden die Kompensationen abgeschlossener Schritte ausgeführt, nachdem der Workflow als fehlgeschlagen markiert wurde. Danach wird `retry_workflow()` ausgelöst, weil der Workflow bereits kompensiert wurde.

## Unterstützte Schritttypen

Kompensationen lassen sich hinzufügen für:

- sequenzielle Schritte `then()`
- Gruppen `parallel()`
- Schritte `for_each()`
- Schritte `run_workflow()`
- Verzögerungsschritte `delay()`
- Signalschritte `wait_for_signal()`
- Workflow-Abhängigkeitsschritte `wait_for_workflow()`

Bei `run_workflow()` und `for_each()` wird die Kompensationsmomentaufnahme gespeichert, nachdem die verschachtelte oder verzweigte Arbeit vollständig abgeschlossen ist.

## `on_cancel()` oder Kompensation

Verwende `compensate_with()`, um Nebenwirkungen abgeschlossener Schritte in umgekehrter Reihenfolge rückgängig zu machen.

Verwende `on_cancel()` als einzelnen Bereinigungshook auf Workflow-Ebene, der bei jedem ausdrücklichen Abbruch des Workflows ausgeführt werden soll.
