← Назад к вопросам

Что такое паттерн SAGA?

2.0 Middle🔥 61 комментариев
#Python Core#Soft Skills

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Паттерн SAGA

SAGA — это архитектурный паттерн для управления транзакциями в распределённых системах, особенно в микросервисной архитектуре. SAGA решает проблему поддержания консистентности данных когда операция охватывает несколько сервисов.

Проблема ACID транзакций в микросервисах

В монолитном приложении можно использовать традиционные ACID транзакции БД. Но в микросервисной архитектуре каждый сервис имеет свою БД, и ACID транзакции через сетевые границы невозможны:

# Проблема: как гарантировать консистентность?
# Операция: заказ платежа + списание денег + резервирование товара
# Каждая часть в разных сервисах!
order_service.create_order()     # Сервис 1
payment_service.charge()          # Сервис 2
inventory_service.reserve()       # Сервис 3

Если payment_service не ответит, как откатить изменения?

Два типа SAGA

1. Хореография (Choreography)

Каждый сервис слушает события других сервисов и самостоятельно инициирует следующий шаг. Сервисы общаются через события (message broker или event bus):

# Order Service
def create_order(order_data):
    order = Order.create(**order_data)
    event_bus.publish("OrderCreated", {"order_id": order.id, "amount": order.total})
    return order

# Payment Service (слушает OrderCreated)
@event_bus.subscribe("OrderCreated")
def handle_order_created(event):
    try:
        transaction = charge_payment(event["amount"])
        event_bus.publish("PaymentProcessed", {"order_id": event["order_id"]})
    except PaymentError:
        event_bus.publish("PaymentFailed", {"order_id": event["order_id"]})

# Inventory Service (слушает PaymentProcessed)
@event_bus.subscribe("PaymentProcessed")
def handle_payment_processed(event):
    try:
        reserve_items(event["order_id"])
        event_bus.publish("OrderCompleted", {"order_id": event["order_id"]})
    except InventoryError:
        event_bus.publish("OrderFailed", {"order_id": event["order_id"]})
        # Может потребоваться компенсирующая транзакция

Преимущества хореографии:

  • Слабая связанность между сервисами
  • Простая для малых систем

Недостатки:

  • Сложно отследить и отладить процесс
  • Циклические зависимости событий
  • Жёсткая связь через события

2. Оркестрация (Orchestration)

Центральный оркестратор (Saga Orchestrator) управляет последовательностью вызовов и знает о каждом шаге:

from dataclasses import dataclass
from enum import Enum

class SagaStep(Enum):
    ORDER_CREATED = "order_created"
    PAYMENT_PROCESSING = "payment_processing"
    INVENTORY_RESERVED = "inventory_reserved"
    COMPLETED = "completed"
    FAILED = "failed"

@dataclass
class Order:
    id: str
    amount: float
    status: SagaStep
    compensations: list  # Для отката

class OrderSagaOrchestrator:
    def __init__(self, order_service, payment_service, inventory_service):
        self.order_service = order_service
        self.payment_service = payment_service
        self.inventory_service = inventory_service

    def execute_saga(self, order_data):
        order = Order(
            id=order_data["id"],
            amount=order_data["amount"],
            status=SagaStep.ORDER_CREATED,
            compensations=[]
        )

        try:
            # Шаг 1: создаём заказ
            self.order_service.create_order(order.id, order.amount)
            order.compensations.append(("cancel_order", order.id))

            # Шаг 2: списываем платёж
            transaction_id = self.payment_service.charge(order.amount)
            order.compensations.append(("refund_payment", transaction_id))

            # Шаг 3: резервируем товар
            self.inventory_service.reserve(order.id)
            order.status = SagaStep.COMPLETED
            return order

        except Exception as e:
            # Откатываем в обратном порядке (компенсирующие транзакции)
            order.status = SagaStep.FAILED
            self.rollback_saga(order)
            raise

    def rollback_saga(self, order):
        """Откатываем состояние через компенсирующие транзакции"""
        for compensation_type, *args in reversed(order.compensations):
            if compensation_type == "cancel_order":
                self.order_service.cancel_order(args[0])
            elif compensation_type == "refund_payment":
                self.payment_service.refund(args[0])

Преимущества оркестрации:

  • Видна вся логика в одном месте
  • Легче отследить и отладить
  • Явная обработка ошибок

Недостатки:

  • Оркестратор становится single point of failure
  • Более тесная связанность
  • Оркестратор требует заботы о его состоянии

Компенсирующие транзакции

Ключевой концепт SAGA — компенсирующие транзакции. Если что-то не удалось, мы не откатываем БД, а выполняем противоположные операции:

# Вместо откатки платежа...
actual_transaction = payment_service.charge(100)

# ...выполняем компенсирующую транзакцию
if inventory_error:
    payment_service.refund(actual_transaction.id)

Когда использовать SAGA

  • Микросервисная архитектура
  • Процессы, охватывающие несколько сервисов
  • Когда 2PC (Two-Phase Commit) недоступен
  • Требуется высокая доступность

Паттерн SAGA — это отличное решение для поддержания консистентности в распределённых системах без полагания на классические ACID транзакции.