
# Kompensation i arbejdsgange

Kompensation lader dig tilføje en rollback-handler til et afsluttet trin i en arbejdsgang. Queuety gemmer et øjebliksbillede af den offentlige tilstand, når trinnet afsluttes, og kører derefter kompensationshandlerne i omvendt rækkefølge, når arbejdsgangen annulleres eller eventuelt mislykkes.

## Metoden `compensate_with()`

Kald `compensate_with()` umiddelbart efter det trin, den skal rulle tilbage:

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

Hvis arbejdsgangen senere annulleres, køres Queuety:

1. `CancelSubscriptionCompensation`
2. `DeleteRemoteUserCompensation`

## Kompensationshandlere

Kompensationshandlere implementerer `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'] );
    }
}
```

Handleren modtager den offentlige arbejdsgangstilstand, som den så ud umiddelbart efter, at det kompenserede trin blev afsluttet. Reserverede interne nøgler medtages ikke.

## Annullering eller fejl

Ved eksplicit annullering køres kompensationer for afsluttede trin altid før den valgfrie handler `on_cancel()`.

Ved fejl køres kompensationer kun, hvis du vælger 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 );
```

Uden `compensate_on_failure()` bevarer en mislykket arbejdsgang sin historik over afsluttede trin og kan prøves igen fra det fejlede trin.

Med `compensate_on_failure()` køres kompensationer for afsluttede trin, efter arbejdsgangen er markeret som mislykket. Derefter kaster `retry_workflow()` en fejl, fordi arbejdsgangen allerede er kompenseret.

## Understøttede trin

Kompensation kan tilføjes til:

- sekventielle trin af typen `then()`
- grupper af typen `parallel()`
- trin af typen `for_each()`
- trin af typen `run_workflow()`
- forsinkelsestrin af typen `delay()`
- signaltrin af typen `wait_for_signal()`
- afhængighedstrin for arbejdsgange af typen `wait_for_workflow()`

For `run_workflow()` og `for_each()` registreres kompensationsøjebliksbilledet, når det indlejrede eller forgrenede arbejde er helt afsluttet.

## `on_cancel()` eller kompensation

Brug `compensate_with()` til at rulle bivirkninger fra afsluttede trin tilbage i omvendt rækkefølge.

Brug `on_cancel()` til én oprydningsfunktion på arbejdsgangsniveau, der skal køres, hver gang arbejdsgangen annulleres eksplicit.
