Какие недостатки у паттерна саги
Что проверяют
Понимаете ли вы, что сага не бесплатная замена распределённой транзакции, а обмен изоляции и атомарности на доступность. Следом почти всегда спрашивают, как вы боретесь с отсутствием изоляции и что делать, если упала сама компенсация.
Как отвечать
Сага разбивает бизнес-операцию на цепочку локальных транзакций в разных сервисах, а при сбое запускает компенсирующие шаги. Отсюда недостатки:
- нет изоляции: промежуточное состояние видно другим запросам, возможны грязные чтения и потерянные обновления. Лечится контрмерами: семантическая блокировка (статус
PENDING), коммутативные операции, повторное чтение перед записью, версионирование; - компенсация это не откат: она выполняет обратное бизнес-действие, и не всё обратимо. Отправленное письмо или выплату не вернуть, поэтому такие шаги ставят после поворотной точки (pivot), за которой сага уже не откатывается;
- конечная согласованность: данные сходятся не сразу, и продукт должен это выдерживать;
- идемпотентность обязательна: брокер доставляет сообщения «хотя бы один раз», каждый шаг и каждая компенсация должны переживать повтор;
- запись и публикация не атомарны: изменить таблицу и отправить событие одной транзакцией нельзя, нужен transactional outbox или CDC через Debezium;
- сложная отладка: в хореографии поток размазан по событиям, без сквозного
traceIdи OpenTelemetry его не восстановить. Оркестратор делает поток явным, но сам становится сервисом со своим состоянием.
В Java это обычно Axon Framework, Eventuate Tram Sagas, Camunda или Temporal, и стоит сказать, почему вы выбрали бы конкретный вариант.
Где спотыкаются
Называют компенсацию роллбэком. Откат стирает изменения, а компенсация пишет новые, и между шагом и компенсацией кто-то уже успел увидеть данные.
Забывают про падение самой компенсации. Её тоже нужно повторять до успеха и уметь отдать сагу на ручной разбор.
Перечисляют только «сложно и медленно». Главный минус, которого ждут, это потеря изоляции, и без него ответ выглядит поверхностным.