
# Kompenzacija poteka dela

Kompenzacija omogoča, da dokončanemu koraku poteka dela dodate obravnavalnik za povrnitev sprememb. Queuety shrani posnetek javnega stanja, ko se ta korak konča, nato pa ob preklicu poteka dela ali po želji ob njegovem neuspehu zažene kompenzacijske obravnavalnike v obratnem vrstnem redu.

## Metoda `compensate_with()`

Pokličite `compensate_with()` takoj za korakom, katerega učinke naj razveljavi:

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

Če je potek dela pozneje preklican, se zažene Queuety:

1. `CancelSubscriptionCompensation`
2. `DeleteRemoteUserCompensation`

## Kompenzacijski obravnavalniki

Kompenzacijski obravnavalniki implementirajo `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'] );
    }
}
```

Obravnavalnik prejme javno stanje poteka dela, kakršno je bilo takoj po dokončanju kompenziranega koraka. Rezervirani notranji ključi niso vključeni.

## Preklic in neuspeh

Ob izrecnem preklicu se kompenzacije dokončanih korakov vedno izvedejo pred izbirnim obravnavalnikom `on_cancel()`.

Ob neuspehu se kompenzacije izvedejo samo, če to izberete:

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

Brez `compensate_on_failure()` neuspešen potek dela ohrani zgodovino dokončanih korakov in ga je mogoče ponoviti od neuspešnega koraka.

Z `compensate_on_failure()` se kompenzacije dokončanih korakov izvedejo, ko je potek dela označen kot neuspešen. Nato `retry_workflow()` sproži izjemo, ker je bil potek dela že kompenziran.

## Podprte vrste korakov

Kompenzacijo je mogoče dodati za:

- zaporedne korake `then()`
- skupine `parallel()`
- korake `for_each()`
- korake `run_workflow()`
- zakasnitvene korake `delay()`
- signalne korake `wait_for_signal()`
- korake odvisnosti poteka dela `wait_for_workflow()`

Pri `run_workflow()` in `for_each()` se posnetek za kompenzacijo zabeleži, ko se gnezdeno ali razvejano delo v celoti zaključi.

## `on_cancel()` ali kompenzacija

Za razveljavitev stranskih učinkov dokončanih korakov v obratnem vrstnem redu uporabite `compensate_with()`.

Za en postopek čiščenja na ravni poteka dela, ki naj se izvede ob vsakem izrecnem preklicu, uporabite `on_cancel()`.
