Как лучше реализовать архитектуру счётчика заказов на BackEnd?
Есть база данных со списком заказов, нужно каждую ( условно ) минуту проверять её и обновлять счета клиентов ( уменьшать количество средств на счету в зависимости от типа заказов и всякие такие мелочи ). Работать эта система должна параллельно с сервером на Django и ещё парой других демонов. Как лучше реализовать такую программу? Какую архитектуру и подход использовать? Сейчас у меня отдельная служба запускает скрипт, который while True проверяет БД, делает все обновления и минуту бездействует time.sleep(60). Как сделать правильно?
Зачем это делать по расписанию если можно сделать событийную систему с помощью брокера сообщений. Можно взять для старта RabbitMQ. А если есть уверенность в себе то лучше Kafka чтобы можно было возвращаться во времени
Данил Кислов, совсем не правильно. Выкинуть таймеры из головы и создавать события по результатам действий: создание заказа, оплата заказа и т.п. и по результату того или иного события делать соответствующее операции. Можно все в одну очередь разложить, можно по разным раскидать
Так в том и дело что таких событий чётких нет, нужно онлайн следить за состоянием заказа, чтобы держать в курсе клиента, как минимум. То есть, скорее всего, полностью свести задачу к конечным состояниям не получится
У заказа стоит поминутный тариф, каждую минуту нужно списывать средства со счёта. Прошу объяснить какие события тут без таймера формализовать, чтобы я мог согласиться)
Данил Кислов, а вот теперь мы перешли вообще в другую предментую область. Заказ это всегда конечный процесс, который заканчивается. В данном случае это следующий шаг - исполнение услуги. И тут идет подписочная модель (subscriptions).
В таком случае самое логичное - держать базу ближайших событий, отправлять их в очередь на исполнение поминутно, и при вызове каждого в транзакции создавать новое событие и удалять старое
У заказа стоит поминутный тариф, каждую минуту нужно списывать средства со счёта.
Не нужно. Правильно хранить время начала тарификации, а баланс вычислять как произведение количества минут прошедшмх с начала тарификации на стоимость минуты, вычтенные из баланса.
Сергей Горностаев, ни в коем случае нельзя так поступать. Ошибка в коде может привести к непредсказуемым последствиям. Баланс всегда должен быть зафиксированным результатом пополнений или списаний
Иван Шумов, как раз обновления данных в БД приводят к неисправимым проблемам чаще, чем вычисления по event source. Ошибку в коде можно устранить и пересчитать по исходным данным, даже если она обнаружилась через полгода, а вот неправильные апдейты уже не откатишь так легко.
Сергей Горностаев, у меня сильное подозрение что мы говорим про одно и то же, но не понимаем друг друга. Я про то что по итогу событий каждый раз должна рассчитываться цифра и фиксироваться где-то в базе. Чтобы не перерасчитывать каждый раз при обращении и минимизировать этот участок. Также про то что изменения итога должны быть инкрементыльны и должен храниться лог операций для валидации текущего состояния и поиска ошибок в проде
Иван Шумов, не. В случае event sourcing'а фиксация промежуточных значений выполняется только в виде snapshot'ов раз в некоторый период времени, а делается это только для экономии ресурсов, чтобы не вычислять баланс пересчётом всех операций за десять лет, например. В остальном в базу только пишутся события и никогда ничего не изменяется и не удаляется.
Сергей Горностаев, окей, я юр-лицо и на мой счет каждую секунду сыпятся переводы средств. Чтобы посмотреть итог надо что - пойти все транзакции собрать чтобы рассчитать итоговую сумму с последнего снапшота? Пример может и дурацкий, но я его привел как то что может помочь нам сойтись в видении
Сергей Горностаев, и даже в кэше агрегат не хранится? это же **здец для высоконагруженных систем с высочайшими требованиями к консистенции. А если там не только сложение и вычитание должно использоваться?