Распределенный биллинг ломается не на тарифах, а на границах консистентности
В распределенной системе нельзя полагаться на «одну правильную запись» в одном сервисе. Счет, списание, начисление, кредитный лимит и статус платежа живут в разных доменах, а значит любая операция должна иметь:
— явный idempotency key;
— журнал переходов состояния;
— компенсацию на случай частичного успеха;
— дедупликацию входящих событий.
Идемпотентность в биллинге — это не рекомендация, а базовый вопрос выживания системы. Повторный webhook, дубль из очереди, таймаут шлюза или ретрай клиента не должны создавать второе списание. Источник истины должен быть один: либо ledger с неизменяемыми проводками, либо строгая state machine, где запрещены «прыжки» между состояниями без контроля версии записи.
Отдельная зона риска — асинхронные синхронизации. Если платеж уже подтвержден, а подписка еще не активирована, система должна уметь жить в промежуточном состоянии. Здесь полезны outbox/inbox-паттерны, атомарная запись события вместе с бизнес-изменением и фоновая репликация через очереди с повторной доставкой.
Давайте разберем, что происходит с транзакцией в момент сетевого сплита шлюза: клиент видит timeout, провайдер успевает провести платеж, а ваша система запускает повтор. Без жесткой дедупликации вы получаете либо двойное списание, либо расхождение между ledger и витриной. Лечится это не «более длинным таймаутом», а проектированием на недоверие к сети и на неизбежные повторы.
Правило простое: сначала фиксация финансового факта, потом все остальное. Если ваша модель данных не позволяет восстановить цепочку событий и объяснить каждую копейку, это не биллинг, а набор несвязанных интеграций.
Подписки: биллинг-лаб
@subscriptions_billing_lab_arb
Распределенный биллинг ломается не на тарифах, а на границах консистентности
Этот пост опубликован в Telegram-канале Подписки: биллинг-лаб. Подписаться можно по ссылке: @subscriptions_billing_lab_arb.