Аномалии данных в SAGA

Поскольку SAGA не блокирует базу данных глобально (как ACID-транзакция), в ней возникают специфические проблемы, которые нужно обрабатывать на уровне кода.

1. Аномалии данных
  • Lost Updates (Потерянные обновления): Две саги одновременно меняют один объект, одна перезаписывает изменения другой.
  • Dirty Reads (Грязные чтения): Одна сага читает данные, которые другая собирается откатывать.

Решение: Использование оптимистичных блокировок с версионированием.

Python
# Пример версионирования для избежания lost updates
def update_user_balance(user_id, amount, expected_version):
    user = get_user_with_version(user_id)
    
    if user.version != expected_version:
        raise OptimisticLockException("User data was modified by another process")
    
    user.balance += amount
    user.version += 1
    save_user(user)
2. Зависшие саги и Тайм-ауты

Что делать, если одна из Retryable транзакций так и не завершилась успешно? Сеть лежит, стороннее API недоступно.

В прошлом уроке уже затрагивали момент с повторами.

После N попыток сервис должен остановиться. Зависшая Сага записывается в отдельную БД или очередь (часто называют Dead Letter Queue), и срабатывает алерт. Дальше инцидент разбирают разработчики или поддержка вручную.

Python
class SagaTimeoutHandler:
    def __init__(self, max_retries=3, timeout_minutes=30):
        self.max_retries = max_retries
        self.timeout_minutes = timeout_minutes
    
    async def handle_stuck_saga(self, saga_id):
        saga = await self.get_saga_state(saga_id)
        
        if saga.retries >= self.max_retries:
            # Лимит исчерпан: Переводим в ручную обработку (DLQ)
            await self.send_to_manual_processing(saga)
            await self.notify_ops_team(saga)
        else:
            # Пробуем еще раз, не забывая про ИДЕМПОТЕНТНОСТЬ!
            await self.retry_saga_step(saga)
Как это реализуют в BigTech?

Строить Оркестратор для SAGA с нуля, обрабатывая все таймауты, оптимистичные блокировки и ретраи вручную — гиблое дело. Яндекс, T-Bank и другие гиганты используют готовые фреймворки. Современный стандарт индустрии — Temporal.io.