
# Workflowcompensatie

Met compensatie kun je een terugdraaiafhandelaar koppelen aan een voltooide workflowstap. Queuety slaat een momentopname van de openbare status op wanneer die stap is voltooid en voert de compensatiehandlers in omgekeerde volgorde uit wanneer de workflow wordt geannuleerd of, optioneel, mislukt.

## De methode `compensate_with()`

Roep `compensate_with()` direct aan na de stap die ongedaan moet worden gemaakt:

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

Als de workflow later wordt geannuleerd, wordt Queuety uitgevoerd:

1. `CancelSubscriptionCompensation`
2. `DeleteRemoteUserCompensation`

## Compensatiehandlers

Compensatiehandlers implementeren `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'] );
    }
}
```

De handler ontvangt de openbare workflowstatus zoals die er direct na voltooiing van de gecompenseerde stap uitzag. Gereserveerde interne sleutels zijn niet inbegrepen.

## Annulering versus mislukking

Bij expliciete annulering worden compensaties voor voltooide stappen altijd uitgevoerd vóór de optionele handler `on_cancel()`.

Bij mislukking worden compensaties alleen uitgevoerd als je daarvoor kiest:

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

Zonder `compensate_on_failure()` behoudt een mislukte workflow de geschiedenis van voltooide stappen en kan deze opnieuw worden geprobeerd vanaf de mislukte stap.

Met `compensate_on_failure()` worden compensaties voor voltooide stappen uitgevoerd nadat de workflow als mislukt is gemarkeerd. Daarna gooit `retry_workflow()` een fout, omdat de workflow al is gecompenseerd.

## Ondersteunde staptypen

Compensatie kan worden gekoppeld aan:

- sequentiële stappen `then()`
- groepen `parallel()`
- stappen `for_each()`
- stappen `run_workflow()`
- vertragingsstappen `delay()`
- signaalstappen `wait_for_signal()`
- workflowafhankelijkheidsstappen `wait_for_workflow()`

Voor `run_workflow()` en `for_each()` wordt de compensatiemomentopname vastgelegd nadat het geneste of vertakte werk volledig is afgerond.

## `on_cancel()` versus compensatie

Gebruik `compensate_with()` om bijwerkingen van voltooide stappen in omgekeerde volgorde ongedaan te maken.

Gebruik `on_cancel()` voor één opruimhaak op workflowniveau die moet worden uitgevoerd telkens wanneer de workflow expliciet wordt geannuleerd.
