Проект представляет собой python пакет, для его установки в терминале нужно выполнить команду
pip install .
. Для установки в dev режиме с возомжностью форматирования кода без переустановки
пакета можно использовать команду pip install -e .
.
Для запуска сервера после установки нужно ввести команду sweets_store.api
, сервер будет
слушать соединения на порте 8080.
sweets_store/db/engine - соединение с базой данных, утилиты для установки и разрыва соедиения при старте
и остановке сервера.
sweets_store/db/tables - описание всех таблиц, каждая таблица в своем модуле.
sweets_store/db/alembic - конфигурация alembic и миграции.
sweets_store/api/app.py - инициализация сервера и описание ручек. Функция для запуска сервера.
sweets_store/api/__main__ - входная точка проекта.
sweets_store/api/handlers - реализованные обработчики со связанной с ними логикой. Сами
обработчики лежат в sweets_store/api/handlers/<name>/endpoints, name определяет логические блоки.
В каждом из модулей sweets_store/api/handlers/<name> следующая структура:
- endpoints - реализованные обработчики запросов
- queries - запросы к БД. Запросы выделяются в отдельный модуль от ручек в связи с частой необходимостью переиспользования
- datatypes - pydantic модели для валидации данных
- constants - константы(типы курьеров, коэффициенты оплаты и др.)
- utils - логика предметной области(например функции подбора заказов, расчета заработка и др.)
В sweets_store/api/handlers/base хранится общая логика, базовые view, шаблоны часто исполняемых запросов к БД.
В sweets_store/utils хранятся глобальные утилитные функции необходимые во всем проекте, логически объединены в модули.
- sweets_store/utils/data_parsing - функции относящиеся к парсингу данных, в частности там лежит функция формирующая отчет об ошибках валидации
- sweets_store/uitls/dates - модуль по работе с датами
Файлы конфигурации:
pyproject.toml - конфиги для isort и black
setup.cfg - конфиг для mypy
setup.py - описание пакета
black .
- запуск линтера стилей кода в проекте
isort .
- запуск линтера для импортов
mypy
- проверка ошибок типов
alembic upgrade head
- запуск миграций, необходимо запускать команду в папке
/sweets_store/db/alembic
В базе данных реализовано всего три таблицы, orders - данные о заказах, из добавленных полей помимо базовых здесь bundle_id - связь многие к 1 с таблицей развозов(много заказов к 1 развозу), и complete_time - время завершения заказа.
Таблица couriers - данные о курьерах, только стандартные поля.
Таблица bundles - таблица с данными о развозах. Присутствуют следующие поля:
- bundle_id - primary key
- courier_id - связь с курьером, многие к 1(много развозов к 1 курьеру)
- courier_type - тип курьера на момент начала развоза, важно сохранять для расчета заработка
- assign_time - время формирования развоза
- is_completed - флаг, отмечающий развоз как законченный. По сути является производным от статуса окончания всех заказов в развозе, но сильно облегчает поиск развозов с нужным статусом для курьеров
Статус выполненности развоза проверяется и изменяется при изменениях статусов заказов из этого развоза, при запросе на ручку orders/complete и изменении статуса заказа, либо при отмене заказа для курьера при изменении его параметров. В каждом из случаев после изменения статусов заказов проверяется, что в соотвествующем развозе еще есть незакрытые заказы, иначе развоз омтечается законченным.
Ошибки валидации имеют следующую структуру, помимо описанных полей с возвращаемыми id присутствуют поля, относящиеся к каждому объекту по его id. То есть отчет по ошибкам валидации представляет собой словарь, в котором ключом является id объекта, а справа словарь, в котором ключу - имени валидируемого поля, в соответствие поставлена ошибка валидации. Пример на скрине ниже:
Явная проверка на входные данные проводится в основных трех ручках, где в базу пишутся новые объекты/обновляются поля старых. Это ручки POST /couriers, POST /orders и PATCH /couriers/{courier_id}.
Формат немного отличается для patch запроса т.к. для него допустимо не передавать некоторые из полей. Если передано невалидное поле - возвращается такой же отчет об ошибках валидации как в первых двух ручках, но если передать одно или несколько необязательных полей со значением null, то ошибка валидации будет описана в поле __core__ где будут перечислены все такие поля.
Все ручки возвращающие даты возвращают их в необходимом формате соотвествующем ISO 8601 и RFC 3339, но всегда для нулевой +00:00 таймзоны. Ручка complete_time принимает дату в любой таймзоне (+HH:MM), приводит ее к GMT(+00:00) и в таком виде пишет в БД. При возврате обратно дата также возвращается в нормализованном виде, +00:00 обозначается в ответах как 'Z'.
Деплой вручную. Основные шаги:
-
Подключамся к серверу, устанавливаем необходимые пакеты:
sudo apt-get update
sudo apt-get install mosh git htop python3.9 python3-pip
-
Стягиваем проект с github:
git clone https://github.com/zhurbeySA/backend_school_project.git
-
Создаем новую виртуальную среду:
sudo apt-get install -y python3-venv
python3 -m venv env
. ./env/bin/activate
- активируем виртуальную среду -
Устанаавливаем зависимости:
pip install .
- запускаем в корне проекта для установки пакета и необходимых зависимостей -
Поднимаем и настраиваем базу данных:
sudo apt-get install postgresql
sudo -u postgres createuser backend_school
- создаем пользователя backend_school
sudo -u postgres createdb backend_school
- создаем таблицу backend_school
Устанавливаем пароль для пользователя:
psql=# alter user backend_school with encrypted password '12346';
Даем права на базу данных пользователю backend_school:
postgres=# grant all privileges on database backend_school to backend_school;
Создаем файл .env в корне проекта с данными подключения к базе, содержимое:
export DB_SCHEME=postgresql
export DB_USER=backend_school
export DB_PASSWORD=12346
export DB_HOST=localhost
export DB_PORT=5432
export DB_NAME=/backend_school
Устанавливаем переменные окружения:
. ./env
Пароль для пользователя postgres - 12346
- Запускаем миграции:
pip install alembic
- устанавливаем alembic
Переходим в sweets_store/db/alembic и запускаем миграции
alembic upgrade head
- Запускаем сервер
Для запуска и управления состоянием сервера я использовал supervisor
sudo apt-get install supervisor
Создаем файл конфигурации supervisor по пути /etc/supervisor/conf.d/aiohttp.conf. Содержимое на скрине:
После этого выполняем две команды и сервер запущен
sudo supervisorctl reread
sudo supervisorctl update
Сервер перезапускается при возникновении критических ошибок и переазгрузках системы автоматически, для этого в supervisor установлены опции autostart и autorestart = true.
В целом выполнил все задания, за исключением того, что не успел написать тесты и попробовать задеплоить с докером