Архитектурное решение · fintech
Геораспределённый биллинг на Temporal SAGA
Бэкенд / Платформа GoTemporalgRPCKafkaNATSPostgreSQL
callback ─► core · Temporal SAGA ──task queue──► region wallet find/create → parse → FX (replay) → deposit → status → event любой сбой ⇒ LIFO-компенсации · Kafka держит колбэки durable
Проблема
Распределённой платёжно-биллинговой платформе нужно было обрабатывать денежные депозиты по регионам с гарантией exactly-once — переживая отказ региона, сетевые разрывы и дубли колбэков провайдеров — без хрупкого самодельного координатора и без two-phase commit.
Подход
Смоделировал депозит как Temporal SAGA — шестишаговый workflow с LIFO-компенсациями. Операции с кошельком выполняются в регионе, оркестрация остаётся в core; запросы роутятся по региону через task queues и gRPC fire-and-forget, а транспорт core↔region спроектирован и сравнён в двух вариантах — региональный Temporal-воркер по WAN и NATS request/reply. У каждой activity свой ключ идемпотентности, FX-курс фиксируется на первом исполнении и реплеится из event history на ретраях, а колбэки провайдеров приходят через Kafka — доставка переживает даунтайм Temporal.
Результат
Межрегиональные депозиты, эффективно ровно один раз — сбойный шаг запускает компенсации, зависший workflow ограничен таймаутом, дубли колбэков дедупятся по workflow ID, а недоступный регион деградирует безопасно с алертами, не теряя и не задваивая деньги.
Доказательства
Описано в истории работы (Korvax, 2022–настоящее время). Трейд-оффы дизайна — сравнение транспортов core↔region, семантика компенсаций и матрица отказов — разбираемы в звонке.
Доступно для: приватный разбор
Координатор — это сам workflow: Temporal сохраняет каждый шаг, поэтому после падения исполнение продолжается с последней завершённой activity, а не переигрывает side-effects. Идемпотентность на каждой activity плюс LIFO-компенсации — вот что делает «зачислить депозит ровно один раз» правдой между регионами, даже когда колбэки at-least-once, а целый регион может исчезнуть на середине.