Комментарии 8
Блин. Есть всякие java с соответствующей обвязкой фреймворками \ библиотеками. Ещё и куча требований есть к начинающим программистам: чистый код, всякие архитектурные шаблоны. И то бизнес нос воротит.
А вот пример, за что бизнес платит деньги.
Сколько ошибок в проектировании финтех проекта хотите?
Да!
Прям полный список антипаттернов...
Откройте для себя Check Constraint в PostgreSQL, чтобы не делать глупых селектов баланса
Откройте для себя Saga и RabbitMQ хотя бы, чтобы не городить велосипеды на PostgreSQL
Перестаньте хранить денежные единицы во float
Откройте для себя представления в PostgreSQL и модуль крона в нем
Откройте для себя уровни изоляции транзакций и понимание их сайд-эффектов
Перестаньте писать спагетти-код
разберём по пунктам:
CHECK constraint есть, balance_non_negative CHECK (balance >= 0) прямо в схеме в статье.
Осознанный выбор в пользу PostgreSQL как единственного источника правды. Unique constraint даёт атомарность которую Saga с RabbitMQ без persistence не даст.
именно про это написан отдельный раздел. NUMERIC(38,18) везде, _validate_amount явно отклоняет float с сообщением "float не допускается".
Представления и pg_cron, вкусовщина, не антипаттерн.
Уровни изоляции, REPEATABLE READ в balance check, NOWAIT на всех блокировках, lock_timeout, явный catch на DeadlockDetected.
Спагетти-код, не понял к чему это.
Такое ощущение, что вы комментировали не читая статью.
Мой косяк. Посмотрел на первый запрос.
"Unique constraint даёт атомарность которую Saga с RabbitMQ без persistence не даст." с чего вдруг? Создаете ключ идемпотентности и вперед. Ключ есть в базе - обрабатываете сообщение, ключа нет - nack. Мало того, при большом объеме транзакций, у вас база просто захлебнется от того количества запросов, которые к ней идут. Это велосипед, причем крайне сомнительный
Зачем вам 18 знаков после запятой, если вы храните в неделимых единицах криптовалюты?
Представления и pg_cron позволяют нормально читать без портяночных запросов в коде
Претензия обоснована. Не увидел.
Как-нибудь поймете
2. Unique constraint в PostgreSQL и есть idempotency key. RabbitMQ без persistence, дополнительная точка отказа. Нагрузка, осознанный трейдофф, PgBouncer и партиционирование в бэклоге.
3. Храним в ETH, провайдер присылает сконвертированное. NUMERIC(38,18), worst case для любого ERC-20 с 18 decimals.
5. REPEATABLE READ, NOWAIT, lock_timeout, statement_timeout, catch на LockNotAvailable, QueryCanceled, DeadlockDetected, всё в коде.
Так и предаствляю владельца бизнеса: всё было хорошо, пришёл какой-то программист, стало плохо, переписал всё, теперь стало ещё хуже и никто не понимает написанный код. true story
Хотел почитать, но слоп слоповый

At-least-once. Это не баг провайдера. Это ваша архитектурная проблема