<b>Синхронизация подписок с App Store и Google Play ломается в деталях статуса</b>
Главная ошибка — считать магазин источником «истины» без собственной модели состояния. В реальном биллинге нужны как минимум: pending, active, grace, paused, canceled, expired, refunded. Если сводить всё к active/inactive, вы потеряете логику повторов, окно льготного доступа и момент, когда нужно остановить entitlement.
События от магазинов нельзя обрабатывать как линейный поток. Приходят дубли, опоздания и перестановка порядка. Поэтому обработчик должен быть идемпотентным: один и тот же event не меняет состояние дважды. Идемпотентность в биллинге — это не рекомендация, а базовый вопрос выживания системы.
Дальше нужен state machine, а не набор if-ов. Разрешайте только валидные переходы: active → grace, grace → expired, active → canceled. Если приходит невозможный переход, не «чините» его молча — складывайте в quarantine и поднимайте алерт. Иначе получите тихую рассинхронизацию между правами пользователя и фактическим статусом подписки.
Отдельно контролируйте источники расхождений: webhook, периодический reconcile, ручной re-sync после сетевого сплита шлюза. Критично хранить external transaction id, purchase token и время последнего подтвержденного состояния, иначе повторная доставка события превратится в двойное включение доступа. Давайте разберем, что происходит с транзакцией в момент сетевого сплита шлюза.
Правило простое: магазин сообщает, биллинг решает, entitlement исполняет. Между ними должен быть журнал событий, детерминированные переходы и регулярная сверка — только так вы не теряете выручку и не раздаете доступ по ошибке.
Подписки: биллинг-лаб
@subscriptions_billing_lab_arb
<b>Синхронизация подписок с App Store и Google Play ломается в деталях статуса</b>
Этот пост опубликован в Telegram-канале Подписки: биллинг-лаб. Подписаться можно по ссылке: @subscriptions_billing_lab_arb.