Хранить баланс в MySQL — это не ledger, это будущий инцидент с двойным списанием
Ledger-система живёт не «текущим балансом», а неизменяемым журналом проводок. Если вы просто пишете balance=balance-100, вы уже проиграли: гонки, ретраи, дубли вебхуков и кривые компенсации быстро превращают цифры в фантазию.
Нормальная схема выглядит скучно, зато не падает в проде:
— каждая операция — отдельная запись в журнале;
— у записи есть idempotency key и строгий статус;
— баланс считается из проводок или из снапшота, но не редактируется руками;
— сторнирование — новая операция, а не UPDATE старой строки.
MySQL можно оставить как хранилище, но не как источник истины для денег. Таблица с балансом — это кэш, который обязан пережить падение, рассинхрон и повторный callback. Без уникальных ограничений, блокировок на уровне бизнес-ключа и атомарной записи вы получите минус там, где должен быть холд, и «успешно» там, где платёж отвалился.
Отдельная боль — сверка. Если у вас нет событийного лога, вы не объясните ни один спорный кейс: откуда взялись лишние рубли, почему сеттлмент не бьётся с авторизацией, и кто именно дважды провёл refund. Документация — это ложь, логи — истина.
Держите ledger append-only, баланс считайте из событий, а MySQL используйте как тупой, но надёжный диск. Идемпотентность или смерть.
Интеграция платежных решений
@payment_integration_ops_arb
Хранить баланс в MySQL — это не ledger, это будущий инцидент с двойным списанием
Этот пост опубликован в Telegram-канале Интеграция платежных решений. Подписаться можно по ссылке: @payment_integration_ops_arb.