
# Kompenzace workflow

Kompenzace umožňuje připojit k dokončenému kroku workflow obslužnou rutinu pro vrácení změn. Queuety po dokončení kroku uloží snímek veřejného stavu a při zrušení workflow nebo případně při jeho selhání spustí kompenzační obslužné rutiny v opačném pořadí.

## Metoda `compensate_with()`

Zavolejte `compensate_with()` bezprostředně za krokem, který má vrátit zpět:

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

Pokud bude workflow později zrušeno, spustí se Queuety:

1. `CancelSubscriptionCompensation`
2. `DeleteRemoteUserCompensation`

## Kompenzační obslužné rutiny

Kompenzační obslužné rutiny implementují `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'] );
    }
}
```

Obslužná rutina obdrží veřejný stav workflow tak, jak vypadal bezprostředně po dokončení kompenzovaného kroku. Vyhrazené interní klíče nejsou zahrnuty.

## Zrušení a selhání

Při výslovném zrušení se kompenzace dokončených kroků vždy spustí před volitelnou obslužnou rutinou `on_cancel()`.

Při selhání se kompenzace spustí jen tehdy, pokud ji výslovně povolíte:

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

Bez `compensate_on_failure()` zůstane historie dokončených kroků neúspěšného workflow zachována a workflow lze opakovat od neúspěšného kroku.

S `compensate_on_failure()` se kompenzace dokončených kroků spustí poté, co je workflow označeno jako neúspěšné. Poté `retry_workflow()` vyvolá chybu, protože kompenzace workflow už proběhla.

## Podporované typy kroků

Kompenzaci lze připojit k těmto krokům:

- sekvenčním krokům `then()`
- skupinám `parallel()`
- krokům `for_each()`
- krokům `run_workflow()`
- krokům s prodlevou `delay()`
- krokům se signálem `wait_for_signal()`
- krokům závislosti workflow `wait_for_workflow()`

U `run_workflow()` a `for_each()` se snímek pro kompenzaci zaznamená až po úplném dokončení vnořené nebo větvené práce.

## `on_cancel()` a kompenzace

Pomocí `compensate_with()` vracejte vedlejší účinky dokončených kroků v opačném pořadí.

Pomocí `on_cancel()` nastavíte jedinou obslužnou rutinu pro úklid na úrovni workflow, která se spustí při každém jeho výslovném zrušení.
