Распределенный биллинг ломается не на расчетах, а на консистентности данных
В биллинге один и тот же счет может рождаться в API, очереди, воркере и верификационном джобе. Если у этих контуров нет единого правила записи, вы получаете дубли списаний, «потерянные» инвойсы и вечные расхождения между ledger и витриной.
Базовые опоры здесь простые:
— единый источник истины для финансового события;
— идемпотентный ключ на каждый charge/renewal/refund;
— транзакционная запись проводок и статуса в одной границе атомарности;
— outbox-паттерн, чтобы не терять событие между БД и шиной;
— строгая семантика retry: повторяем только безопасные операции, а не бизнес-эффект. Идемпотентность в биллинге — это не рекомендация, а базовый вопрос выживания системы.
Особая зона риска — частично успешные сценарии: списание прошло, а callback от шлюза не дошел; подписка продлена, но entitlement не выдан; refund создан, но не попал в отчетность. Такие кейсы нельзя «дописывать руками» в админке без журналирования: любое ручное исправление должно оставлять неизменяемый audit trail и компенсирующую проводку.
Если система масштабируется, не пытайтесь добиться сильной консистентности везде. Разведите критичный финансовый контур и eventual-consistent витрины: пользователю можно показать «обновляется», но ledger обязан оставаться строгим. Давайте разберем, что происходит с транзакцией в момент сетевого сплита шлюза: именно там рождаются самые дорогие дубли.
Правило одно: сначала защищаете финансовую запись, потом синхронизируете все остальное.
Подписки: биллинг-лаб
@subscriptions_billing_lab_arb
Распределенный биллинг ломается не на расчетах, а на консистентности данных
Этот пост опубликован в Telegram-канале Подписки: биллинг-лаб. Подписаться можно по ссылке: @subscriptions_billing_lab_arb.