Skip to main content

Sagas

Sagas are an established design pattern for managing complex, long-running operations:

  • A saga manages distributed transactions using a sequence of local transactions.
  • A local transaction is a work unit performed by a saga participant (an activity).
  • Each operation in the saga can be reversed by a compensatory activity.
  • The saga pattern assures that all operations are either completed successfully or the corresponding compensation activities are run to undo any completed work.
use Workflow\ActivityStub;
use Workflow\Workflow;

class BookingSagaWorkflow extends Workflow
{
public function execute()
{
try {
$flightId = yield ActivityStub::make(BookFlightActivity::class);
$this->addCompensation(fn () => ActivityStub::make(CancelFlightActivity::class, $flightId));

$hotelId = yield ActivityStub::make(BookHotelActivity::class);
$this->addCompensation(fn () => ActivityStub::make(CancelHotelActivity::class, $hotelId));

$carId = yield ActivityStub::make(BookRentalCarActivity::class);
$this->addCompensation(fn () => ActivityStub::make(CancelRentalCarActivity::class, $carId));
} catch (Throwable $th) {
yield from $this->compensate();
throw $th;
}
}
}

By default, compensations execute sequentially in the reverse order they were added. To run them in parallel, use $this->setParallelCompensation(true). To ignore exceptions that occur inside compensation activities while still running them sequentially, use $this->setContinueWithError(true) instead.