Тестовое задание Billing на Go

Тестовое задание Billing на Go

@ChatGpt

Микросервис баланса пользователей.

Приложение хранит в себе идентификаторы пользователей и их баланс. Взаимодействие с ним осуществляется исключительно с помощью брокера очередей.

По требованию внешней системы, микросервис может выполнить одну из следующих операций со счетом пользователя:

Списание

Зачисление

Перевод от пользователя к пользователю (будет плюсом, но не обязательно)


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


После проведения любой из этих операций генерируется событие-ответ в одну из очередей.


Основные требования к воркерам:


Код воркеров должен безопасно выполняться параллельно в разных процессах

Воркеры могут запускаться одновременно в любом числе экземпляров и выполняться произвольное время

Все операции должны обрабатываться корректно, без двойных списаний, отрицательный баланс не допускается

В пояснительной записке к выполненному заданию необходимо указать перечень используемых инструментов и технологий, способ развертки приложения, общий механизм работы (интерфейсы ввода/вывода)


Будет плюсом покрытие кода юнит-тестами.


Требования к окружению: Язык программирования: Go Можно использовать: любые фреймворки, реляционные БД для хранения баланса, брокеры очередей, key-value хранилища.


Особенности

Сервис поддерживает обработку паники.

Сервис поддерживает создание и хранение журнала выполненных операций.

Сервис поддерживает полную консистентность данных

Сервис поддерживает graceful shutdown.

Сервис НЕ поддерживает Heartbeat для базы данных.

На момент старта сервиса, должен быть уже запущен NATS.


Используемые компоненты

MySQL - для хранения данных

NATS - брокер сообщений


API

Ответ на каждый запрос включает статус его выполнения: 0. Операция прошла успешно


1.Неизвестная ошибка

2.Операция устарела

3.Для выполнения операции недостаточно средств

4.Аккаунт не найден


Credit

Списание средств со счета.


Subject/Queue - bank.credit

Request: {"uid":1,"account":1,"amount":10}

Response: {"status":1}

Debit

Зачисление средств на счет.


Subject/Queue - bank.debit

Request: {"uid":1,"account":1,"amount":10}

Response: {"status":1}


Transfer

Перевод средст с одного счета на другой.


Subject/Queue - bank.transfer

Request: {"uid":1,"src":1,"dst":2,"amount":10}

Response: {"status":1}

Acquire

Блокировка средств.


Subject/Queue - bank.acquire

Request: {"uid":1,"account":1,"amount":10}

Response: {"status":1}


Commit

Подтверждение блокированных средств.


Subject/Queue - bank.commit

Request: {"uid":1,"account":1}

Response: {"status":1}


Rollback

Возврат блокированных средств.


Subject/Queue - bank.rollback

Request: {"uid":1,"account":1}

Response: {"status":1}


Принцип работы

Для достижения идемпотентности, в каждой операции должен присутствовать ее уникальный номер uid. Каждая операция, при записи в базу данных, регистрирует действие в таблице истории. При существовании одинакового ключа (work_index) происходит ошибка базы данных, которую мы трактуем, как устаревание операции (идемпотентный случай). Аналогчно работает и таблица активов.


В сервисе используется пакет доступа к базе данных github.com/adverax/echo/database/sql, который позволяет эмулировать вложенные транзакции, а также хранить область видимости в контексте. Это позволяет нам осуществлять декомпозицию функционала работы с базой на отдельные функции, не заботясь о контексте выполнения запросов.

Для каждой таблицы используется собственный менеджер.

База данных

База содержит следующие таблицы:

  • account - текущее состояние счета пользователя
  • asset - зарезервированные средства. Для удовлетворения требования идемпотентности, таблица содержит уникальный индекс work_index (account, uid).
  • history - журнал выполненных операций. Для удовлетворения требования идемпотентности, таблица содержит уникальный индекс work_index (account, uid, op).


Брокер

В качестве брокера сообщений используется NATS (без гарантированной доставки сообщений). Для упрощения реализации каждый тип операции имеет собственный Subject и Queue. Множество воркеров подключаются к одной и той же очереди, что позволяет нам организовать конкурентный захват сообщения. Полученное сообщение брокер делегирует банку для дальнейшей обработки, после чего формирует ответ, который возвращается брокеру. Таким образом, каждый endpoint брокера по существу является простым адаптером со следующей логикой работы:

  • Декодировать данные
  • Вызвать метод банка
  • Кодировать данные и вернуть их брокеру.


Комментарии

Для достижения максимальной производительности можно было перенести логику операций в хранимые процедуры.


Установка

  • Установить требуемые библиотеки
  • Скомпилировать сервис
  • Создать базу данных (перейти в каталог database и выполнить команду: mysql -uMyName -pMyPassword < create.sql).
  • Настроить файл конфигурации
  • Запустить NATS.
  • Запустить сервис на выполнение Развертывания как такового не требуется - достаточно просто использовать выполнимый файл.


Тесты

Для основных методов менеджеров написаны модульные тесты. Эти тесты были написаны на скорую руку, поэтому качество их кода оставляет желать лучшего. Однако, они позволяют проверить работоспособность sql кода.

Для запуска тестирования необходимо сделать клон базы данных под именем billing_test.



Report Page