Как устроен оркестратор, управляющий задачами для платежей
Что проверяют
Понимаете ли вы, что платёж это длинный процесс из нескольких шагов с внешними участниками, и любой шаг может закончиться неизвестным результатом. Следом спрашивают про таймаут от банка: деньги списались или нет, и как не списать их дважды.
Как отвечать
Опишите платёж как конечный автомат: CREATED, AUTHORIZED, CAPTURED, FAILED, REFUNDED плюс PENDING для неизвестного исхода. Переходы разрешены только по таблице, состояние хранится в базе, обычно PostgreSQL. Затем ключевые механизмы:
- идемпотентность: клиент присылает ключ идемпотентности, сервис хранит его под уникальным индексом, повторный запрос получает прежний результат. Тот же ключ уходит провайдеру;
- сага вместо распределённой транзакции: каждый шаг локален, у каждого есть компенсация, например отмена авторизации или возврат;
- transactional outbox: смена статуса и событие пишутся в одной транзакции, отдельный воркер переносит событие в Kafka или RabbitMQ;
- воркеры: пул goroutine забирает задачи через
SELECT ... FOR UPDATE SKIP LOCKED, у каждого внешнего вызоваcontext.WithTimeout, отмена пробрасывается вниз по цепочке; - ретраи: только для временных ошибок, с экспоненциальной задержкой, джиттером и лимитом попыток;
- сверка: фоновая задача опрашивает провайдера по зависшим
PENDINGи сверяет итоги с реестром банка.
Можно упомянуть готовые движки: Temporal с Go SDK берёт на себя хранение состояния шагов и ретраи. Суммы храните в целых минорных единицах (int64 в копейках) или десятичном типе, но не во float64.
Где спотыкаются
Считают таймаут ошибкой и повторяют запрос к банку без ключа. Если деньги уже списаны, клиент заплатит дважды. Таймаут означает неизвестный статус, его разрешает сверка или повтор с тем же ключом идемпотентности.
Обещают «транзакцию на всю цепочку». Между сервисами и внешним провайдером её нет, согласованность достигается сагой и компенсациями.
Публикуют событие в брокер отдельно от записи в базу. Сбой между двумя операциями даёт рассинхрон: деньги списаны, а уведомления и учёт об этом не знают.