Система предназначена для расчета бонусных начислений и ведения накопительного бонусного счета пользователя и состоит из следующих сервисов:
- Сервис лояльности
Gophermart
- Сервис начисления баллов лояльности
Accrual/Mockaccrual
(запросы к нему выполняются через предоставленное им REST API и реализация сокрыта)
Краткий сценарий использования:
- Пользователь регистрируется в системе лояльности
Gophermart
. - Совершая покупки пользователь загружает в систему
Gophermart
номера заказов. - Система
Gophermart
направляет номера заказов в систему начисления баллов лояльностиAccrual
. Accrual
производит расчет баллов лояльности.Accrual
может вернуть ответ без баллов лояльности со статусомPROCESSING
.- Полученные ответы от
Accrual
обрабатываются в зависимости от статуса ответа. - У каждого пользователя ведётся баланс его баллов лояльности.
- Пользователь при наличии баллов лояльности может потратить их на покупки (списав на определенный заказ)
Схема связей таблиц в базе данных.
Для взаимодействия с сервисами предоставляется HTTP API.
Используемые технологии:
-
Docker/Docker compose
-
PostgreSQL/pgx
-
Gin
-
Middleware
-
JWT auth
Запуск возможен с использованием cli флагов и env переменных
-
SERVER_ADDRESS
(-a
):Адрес сервера: По умолчанию —localhost:8090
. -
LOG_LEVEL
(-l
):Уровень логирования: По умолчанию установлен наinfo
. -
ACCRUAL_SYSTEM_ADDRESS
(-b
): Адрес внешнего сервиса расчета бонусных баллов: По умолчанию —http://localhost:8080/api/orders/
. -
DATABASE_URI
(-d
):Данные для подключения к базе данных: По умолчанию установлен напусто
. -
FILE_STORAGE_PATH
(-f
):Путь сохранения файла локального хранения данных: По умолчанию установлен на/tmp/gopher-mart-db.json
.
Проект прежде всего учебный, поэтому считаю возможным уточнить некоторые решенные нюансы:
-
Система
accrual
была представлена "черным ящиком", внутреннее устройство неизвестно (известны только форматы ответов). -
Основной проблемой было то, что время ответа сервиса было рандомным и чтобы пользователь не повис в ожидании ответа, нужно было разработать механику ответов клиенту. Для этого запрос к сервису осуществлялся асинхронно
-
Потребовалось отслеживать какие номера заказов отправлялись в
accrual
систему, чтобы избежать отправки дублирующих запросов. Для этого в таблицеorders
были добавлены поля для отслеживания состояния (готовность к отправке вaccrual
и т.д.)
В рамках одного запросы происходит выборка заказов, у которых НЕ окончательный статус и имеется статус true
для возможности отправки в accrual
.
В свою очередь при получении ответа от accrual
происходит обновление заказа в соответствии с полученным статусом:
Т.е. если у заказа статус не являются окончательным - флаг возможности отправки в accrual
снова меняется на true
, таким образом заказ будет повторно обработан.
В итоге gophermart
не отправляет в accrual
уже отправленные заказы.
- Для таблицы
balance
первоначально были созданы неименованныеconstraint
:current >= 0
иwithdrawn >= 0
.
Однако был обнаружен баг, при котором общая проверка CheckViolation
одинаково понимала и нарушение для баланса и для списаний.
Соответственно указанные constraints
были заменены на именованные, при этом добавлена проверка конкретно для constraint
баланса:
-
В проекте старался обработать все возможные ошибки и залогировать их выводя в cli, а также сохраняя в во временный файл при помощи конфигурации logrus и lumberjack. Убедился, насколько это упростило отладку приложения.
-
Так как в проекте предполагаются финансовые операции был использован пакет shopspring/decimal
- Интеграционные тесты (testcontainers)
- Godoc