/backend_school_project

Project test task for yandex backend school

Primary LanguagePython

Backend school intro project

Setup and run

Проект представляет собой python пакет, для его установки в терминале нужно выполнить команду pip install .. Для установки в dev режиме с возомжностью форматирования кода без переустановки пакета можно использовать команду pip install -e ..
Для запуска сервера после установки нужно ввести команду sweets_store.api, сервер будет слушать соединения на порте 8080.

Project structure

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

Tables

В базе данных реализовано всего три таблицы, 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 и изменении статуса заказа, либо при отмене заказа для курьера при изменении его параметров. В каждом из случаев после изменения статусов заказов проверяется, что в соотвествующем развозе еще есть незакрытые заказы, иначе развоз омтечается законченным.

Validation errors

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

1

Явная проверка на входные данные проводится в основных трех ручках, где в базу пишутся новые объекты/обновляются поля старых. Это ручки POST /couriers, POST /orders и PATCH /couriers/{courier_id}.

Формат немного отличается для patch запроса т.к. для него допустимо не передавать некоторые из полей. Если передано невалидное поле - возвращается такой же отчет об ошибках валидации как в первых двух ручках, но если передать одно или несколько необязательных полей со значением null, то ошибка валидации будет описана в поле __core__ где будут перечислены все такие поля.

2

Dates handling

Все ручки возвращающие даты возвращают их в необходимом формате соотвествующем ISO 8601 и RFC 3339, но всегда для нулевой +00:00 таймзоны. Ручка complete_time принимает дату в любой таймзоне (+HH:MM), приводит ее к GMT(+00:00) и в таком виде пишет в БД. При возврате обратно дата также возвращается в нормализованном виде, +00:00 обозначается в ответах как 'Z'.

Deploy

Деплой вручную. Основные шаги:

  1. Подключамся к серверу, устанавливаем необходимые пакеты:
    sudo apt-get update
    sudo apt-get install mosh git htop python3.9 python3-pip

  2. Стягиваем проект с github:
    git clone https://github.com/zhurbeySA/backend_school_project.git

  3. Создаем новую виртуальную среду:
    sudo apt-get install -y python3-venv
    python3 -m venv env
    . ./env/bin/activate - активируем виртуальную среду

  4. Устанаавливаем зависимости:
    pip install . - запускаем в корне проекта для установки пакета и необходимых зависимостей

  5. Поднимаем и настраиваем базу данных:
    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

  1. Запускаем миграции:
    pip install alembic - устанавливаем alembic

Переходим в sweets_store/db/alembic и запускаем миграции
alembic upgrade head

  1. Запускаем сервер
    Для запуска и управления состоянием сервера я использовал supervisor
    sudo apt-get install supervisor

Создаем файл конфигурации supervisor по пути /etc/supervisor/conf.d/aiohttp.conf. Содержимое на скрине:

3

После этого выполняем две команды и сервер запущен
sudo supervisorctl reread
sudo supervisorctl update

Run server on system startup

Сервер перезапускается при возникновении критических ошибок и переазгрузках системы автоматически, для этого в supervisor установлены опции autostart и autorestart = true.

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