
# Arbetsflödeskompensation

Med kompensation kan du koppla en återställningshanterare till ett slutfört arbetsflödessteg. Queuety sparar en ögonblicksbild av det offentliga tillståndet när steget är klart och kör sedan kompensationshanterarna i omvänd ordning när arbetsflödet avbryts eller, om du väljer det, när det misslyckas.

## Metoden `compensate_with()`

Anropa `compensate_with()` direkt efter steget som ska återställas:

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

Om arbetsflödet avbryts senare körs Queuety:

1. `CancelSubscriptionCompensation`
2. `DeleteRemoteUserCompensation`

## Kompensationshanterare

Kompensationshanterare implementerar `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'] );
    }
}
```

Hanteraren får det offentliga arbetsflödestillståndet så som det såg ut direkt efter att steget som kompenseras hade slutförts. Reserverade interna nycklar inkluderas inte.

## Avbrytning jämfört med fel

Vid uttrycklig avbrytning körs alltid kompensationsåtgärder för slutförda steg före den valfria hanteraren `on_cancel()`.

Vid fel körs kompensationsåtgärder endast om du väljer det:

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

Utan `compensate_on_failure()` behåller ett misslyckat arbetsflöde historiken över slutförda steg och kan göras om från steget som misslyckades.

Med `compensate_on_failure()` körs kompensationsåtgärder för slutförda steg efter att arbetsflödet markerats som misslyckat. Därefter kastar `retry_workflow()` ett undantag eftersom arbetsflödet redan har kompenserats.

## Stegtyper som stöds

Kompensation kan kopplas till:

- sekventiella steg av typen `then()`
- `parallel()`-grupper
- `for_each()`-steg
- `run_workflow()`-steg
- fördröjningssteg `delay()`
- signalsteg `wait_for_signal()`
- steg för arbetsflödesberoenden `wait_for_workflow()`

För `run_workflow()` och `for_each()` registreras kompensationsögonblicksbilden när det nästlade eller förgrenade arbetet har slutförts helt.

## `on_cancel()` jämfört med kompensation

Använd `compensate_with()` för att återställa sidoeffekter från slutförda steg i omvänd ordning.

Använd `on_cancel()` för en städkrok på arbetsflödesnivå som ska köras varje gång arbetsflödet avbryts uttryckligen.
