
# Darbo eigos kompensavimas

Kompensavimas leidžia prie užbaigto darbo eigos žingsnio pridėti atšaukimo apdorojimo programą. Queuety išsaugo viešosios būsenos momentinę kopiją, kai žingsnis baigiamas, o tada atvirkštine tvarka vykdo kompensavimo apdorojimo programas, kai darbo eiga atšaukiama arba, pasirinktinai, kai ji nepavyksta.

## Metodas `compensate_with()`

Iškart po žingsnio, kurio poveikį reikia atšaukti, iškvieskite `compensate_with()`:

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

Jei darbo eiga vėliau atšaukiama, vykdomas Queuety:

1. `CancelSubscriptionCompensation`
2. `DeleteRemoteUserCompensation`

## Kompensavimo apdorojimo programos

Kompensavimo apdorojimo programos įgyvendina `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'] );
    }
}
```

Apdorojimo programa gauna viešąją darbo eigos būseną tokią, kokia ji buvo iškart užbaigus kompensuojamą žingsnį. Rezervuoti vidiniai raktai neįtraukiami.

## Atšaukimas ir nesėkmė

Aiškiai atšaukus darbo eigą, užbaigtų žingsnių kompensavimo veiksmai visada vykdomi prieš pasirenkamą `on_cancel()` apdorojimo programą.

Nesėkmės atveju kompensavimo veiksmai vykdomi tik pasirinkus šią parinktį:

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

Jei nenaudojate `compensate_on_failure()`, nepavykusios darbo eigos užbaigtų žingsnių istorija išsaugoma, o vykdymą galima pakartoti nuo nepavykusio žingsnio.

Naudojant `compensate_on_failure()`, užbaigtų žingsnių kompensacijos vykdomos po to, kai darbo eiga pažymima kaip nepavykusi. Tada `retry_workflow()` sukelia išimtį, nes darbo eiga jau kompensuota.

## Palaikomi žingsnių tipai

Kompensaciją galima pridėti prie:

- nuoseklių `then()` žingsnių
- `parallel()` grupių
- `for_each()` žingsnių
- `run_workflow()` žingsnių
- delsos žingsnių `delay()`
- signalo žingsnių `wait_for_signal()`
- darbo eigos priklausomybės žingsnių `wait_for_workflow()`

Naudojant `run_workflow()` ir `for_each()`, kompensacijos momentinė kopija įrašoma po to, kai įdėtiniai ar šakoti veiksmai visiškai užbaigiami.

## `on_cancel()` ir kompensacija

Naudokite `compensate_with()` užbaigtų žingsnių šalutiniams poveikiams atšaukti atvirkštine tvarka.

Naudokite `on_cancel()` vienam darbo eigos lygmens valymo veiksmui, kuris turi būti vykdomas kaskart aiškiai atšaukus darbo eigą.
