Saga compensation design

Fail the compensation as well as the original step

A recovery path that only works when every corrective call succeeds is incomplete. Test the state left behind when compensation is rejected or its response is lost.

In this article

Prepare a partially completed workflow

Use synthetic services for stock reservation, payment authorisation and carrier booking. Let the first two steps complete, then make the carrier reject the booking with a definite failure.

Record the identifiers of the committed effects. The coordinator should know which reservation and payment operation need attention, rather than searching for records with similar values.

Confirm the normal recovery policy for this fixture, such as releasing the reservation and requesting the supported payment reversal.

Fail one corrective action

Allow stock release to succeed, then make the payment correction fail temporarily. The saga should remain unresolved with the completed release recorded. A retry must not repeat already resolved business effects unnecessarily.

Next test a permanent rejection, such as a state in which the requested correction is no longer valid. The coordinator should stop automatic retries and route the specific remaining issue to the defined owner.

Keep temporary and permanent cases separate. A single generic exception handler often obscures the difference.

Lose the response after compensation succeeds

In another run, let the payment correction take effect but drop its response. The coordinator now has uncertainty about the recovery itself.

Verify it reuses the compensating operation identifier or reconciles the downstream state before issuing another action. A recovery operation needs the same duplicate protection as the forward operation.

Restart the coordinator during this uncertainty. The durable record should preserve what was attempted and what remains unknown.

Add an irreversible condition

Change the carrier fixture so the booking actually succeeded and collection began before the timeout was resolved. The original cancel-and-release plan may no longer be appropriate.

The saga should enter the documented forward or manual recovery path, with enough context to explain the committed effects. It should not report a successful rollback while fulfilment continues elsewhere.

Inspect every service's final state and the user-facing status. Keep the cases as regression tests for both orchestration and operational tooling. The important result is a correct, explainable partial state when full automatic recovery is impossible.

Primary sources

Microsoft Learn: compensating transactionsAWS Builders' Library: idempotent APIs

References checked 11 September 2026.