Распределенный биллинг ломается не на оплате, а на границах консистентности
Если у вас есть несколько сервисов, очередь событий, платежный шлюз и отдельный ledger, главный риск — не задержка, а двойное списание, потерянный инвойс или «висящий» статус подписки. Идемпотентность в биллинге — это не рекомендация, а базовый вопрос выживания системы.
Ключевой набор правил:
• каждое денежное действие получает устойчивый idempotency key;
• запись в ledger — только через транзакционный commit с проверкой уникальности;
• внешние вызовы отделяются от изменения баланса через outbox/async handoff;
• статус подписки не вычисляется из одного события, а собирается из журнала состояний.
Дальше начинается самое сложное: ретраи, дубли, сетевые сплиты, частичные отказы. Если шлюз ответил таймаутом, это не значит, что платеж не прошел; если consumer получил событие дважды, это не повод дважды начислять кредит. Нужны дедупликация, монотонные переходы статусов и явная модель reconciliation между бухгалтерским контуром и продуктовым контуром.
Отдельно проектируйте dunning как конечный автомат: retry-window, паузы, escalation, остановка на успешном событии и запрет на перескок через стадии. Тогда система не будет «шуметь» повторными списаниями и не превратит временный сбой в revenue leakage.
Если у вас нет единого ledger, строгих ключей идемпотентности и правил восстановления после сплита, консистентность будет случайностью, а не свойством архитектуры.
Подписки: биллинг-лаб
@subscriptions_billing_lab_arb
Распределенный биллинг ломается не на оплате, а на границах консистентности
Этот пост опубликован в Telegram-канале Подписки: биллинг-лаб. Подписаться можно по ссылке: @subscriptions_billing_lab_arb.