TGViewer
Сергей Озеранский Сергей Озеранский @sergeiozeranskii · 2.35K subscribers
Post #597 916
Как устроены биллинг и леджер в tempus.build

tempus.build продаёт минуты CI-раннеров по предоплате. Списание посекундное, ошибки в деньгах недопустимы, а каждая финансовая операция должна быть прозрачна для аудита. Начну с теории, а в следующем посте покажу, как это реализовано.

Немного теории

В заголовке два слова: биллинг и леджер. Это два связанных инструмента, но решающих разные задачи. И прежде чем разбирать их, важно развести ещё одну вещь: биллинг не проводит платежи.

Проведением платежей занимается платёжный провайдер: авторизует карту, списывает деньги, делает расчет. Для tempus.build это внешняя система. Биллинг узнаёт от неё только факт: "от клиента X пришло N денег" — и с этого момента начинается его работа.

Биллинг — это тарификация и учёт. Он знает, сколько стоит секунда раннера, зачисляет пополнения, списывает за выполненные джобы и отвечает на вопрос "сколько у клиента денег сейчас и хватит ли на эту операцию". Его рабочий инструмент — баланс: одно число, которое читают перед каждой операцией и меняют после. Деньги в реальном мире биллинг не двигает, он ведёт их учёт внутри продукта.

Леджер отвечает на вопрос "как мы к этому числу пришли". Это история: журнал всех движений, каждое с суммой, направлением и причиной. В бухгалтерии этой идее очень много лет: ни одна запись в книге не стирается, ошибка исправляется новой записью.

Зачем разделять баланс и леджер? Потому что у них разные, местами противоположные требования.

Состояние должно быть быстрым и атомарным. Перед стартом джобы нужно за один запрос узнать, хватает ли денег, и сразу их зарезервировать, пока конкурирующая операция не сделала то же самое.

История должна быть неизменяемой и полной. По ней разбирают споры с клиентом, сверяют платежи с платёжными системами и банками, ищут баги в расчётах, строят аналитику. Если её можно править задним числом, ей нельзя верить. Это единственный источник истины обо всех движениях средств по балансу аккаунта.

Если хранить только баланс, при любой аномалии нечем объяснить, откуда взялась цифра. Если хранить только историю, каждая проверка "хватает ли денег" превращается в SUM по всей истории под блокировкой в БД. На горячем пути это неприемлемо. Да и просто неудобно.

Поэтому обе сущности живут рядом, но с чёткими ролями: баланс разрешает операции, леджер их объясняет. Главная инженерная задача — чтобы они никогда не разошлись.
  • 👍 3
  • 🔥 3
  • ❤ 2
  • 👏 1
More from @sergeiozeranskii
  1. Sep 24, 2026Еще немного про ускорения. На этот раз про тесты, а точнее про coverage (Python). Библиоте…
  2. Sep 24, 2026Обнаружил, что агенты Claude Code в разных сессиях умеют общаться между собой. У меня сейч…
  3. Sep 23, 2026Возьмем Python-сервис в Kubernetes. Как правило на старте контейнера может проявляться спа…
  4. Sep 23, 2026Сегодня случилось страшное. То, чего я никак не ожидал. За все годы на MacBook со мной так…
  5. Sep 17, 2026Я вот не понимаю, зачем люди идут в OSS и контрибьютят на отвали. Ценности в этом ноль для…
  6. Sep 17, 2026Помните про https://github.com/ozeranskii/httptap? Я писал о нем давно еще - > тут. Наклеп…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →