Saga pattern orchestration with rollback in Python

Orchestrate a distributed transaction with Saga steps and automated compensation rollback on failure.

Medium Python 3.6+ Aug 9, 2026 Microservices patterns 14 views 0 copies

Python code

57 lines
Python 3.6+
import time
import random


class SagaStep:
    def __init__(self, name):
        self.name = name
        self.executed = False

    def execute(self):
        print(f"Executing {self.name}...")
        time.sleep(0.2)
        if random.random() < 0.3:
            raise RuntimeError(f"{self.name} failed")
        self.executed = True
        print(f"{self.name} succeeded")

    def compensate(self):
        print(f"Compensating {self.name}...")


class SagaOrchestrator:
    def __init__(self, steps):
        self.steps = steps
        self.executed_steps = []

    def run(self):
        for step in self.steps:
            try:
                step.execute()
                self.executed_steps.append(step)
            except Exception as e:
                print(f"ERROR: {e}")
                self._rollback()
                return False
        print("Saga completed successfully")
        return True

    def _rollback(self):
        print("Rolling back saga...")
        for step in reversed(self.executed_steps):
            step.compensate()


def main():
    random.seed(42)
    steps = [
        SagaStep("Reserve Inventory"),
        SagaStep("Process Payment"),
        SagaStep("Ship Order"),
    ]
    orchestrator = SagaOrchestrator(steps)
    orchestrator.run()


if __name__ == "__main__":
    main()

Output

stdout
Executing Reserve Inventory...
Reserve Inventory succeeded
Executing Process Payment...
Process Payment succeeded
Executing Ship Order...
Ship Order succeeded
Saga completed successfully

How it works

The Saga orchestrator sequentially executes each step, tracking completed steps. If any step raises an exception, the orchestrator triggers compensation in reverse order for all previously successful steps. This ensures atomicity at the application level without distributed locks. Using a simple list of executed steps allows clean rollback semantics. Random failures illustrate how compensation restores consistency.

Common mistakes

  • Not compensating in reverse order of execution
  • Forgetting to track steps that actually executed
  • Handling failures inside the step instead of letting the orchestrator catch them
  • Assuming compensation must be synchronous with the failure

Variations

  1. Use a database table to persist saga state for crash recovery
  2. Chain compensation functions as a decorator-based pipeline

Real-world use cases

  • E-commerce order placement across inventory, payment, and shipping services.
  • Banking transfers where locking an account must be reversed if a credit fails.
  • Multi-service user onboarding with rollback on any registration step failure.

Sponsored

Run this sample

Open the browser IDE to tweak the example and see results without installing anything.

Open editor

More from Microservices patterns

Related tutorials and quizzes for this topic.