Стек: flask, SQLAlchemy, Alembic, Celery-Beat, Docker, FlaskSocketIO, JS, CSS, HTML
Создано REST API на Flask для каталогизации и структурирования информации по различным веб-ресурсам, а также мониторинга их доступности.
Для работы с базой данных использовалась библиотека flask-SQLAlchemy
и alembic
для миграций. Сериализация и валидация данных осуществляется с помощью Pydantic
. Эта библиотека, как и сам Flask, для меня новые, поэтому возможно не в полной мере использовала её функционал.
Задачи регулярного мониторинга доступности ресурсов и удаления недоступных ресурсов решены с помощью Celery-Beats, в качестве брокера сообщений используется Redis
. Для того чтоб задать критерий удаления, в модель веб-ресурса было добавлено поле для счетчика, который инкрементится при повторной недоступности ресурса или же обнуляется, если ресурс снова становится доступен. Количество раз подряд, когда ресурс был недоступен, после которого ресурс подлежит удалению, задается в файле конфигурации config.yaml
в секции MAX_RETRIES
.
Расписание для каждой периодической задачи задается в секции PERIODIC_TASKS
в поле RUN_SCHEDULE_HOUR
(изначально хотела задавать расписание строкой крон-формата, но не нашла как это сделать, поэтому для упрощения задала возможность лишь указывать через какое n
часов прогонять таски).
Функции, которые стучатся в базу данных, вынесены в отдельный файл services.py
.
Для организации ротации лог-файлов использовался RotatingFileHandler
из стандартного модуля logging
.
На полную реализацию интерфейса приложения к сожалению не хватило времени, сделала больше упор на серверную часть. Реализована только страница для отображения логов в реал-тайм и возможность скачивания файла pdf с логами (файл формируется на клиенте).
-
POST
/resources
- отправить ссылку для обработкиОжидаемый формат тела запроса:
{ "url": "https://vk.com" }
-
POST
/resources
- отправить zip архив с cvs-файлом с ссылками для обработкиФайл передается с
content-type multipart/form-data
в поле с названиемfile
. -
POST
/resources/<resource_uuid: int>
- сохранить скриншот для ссылки с переданным uuid -
GET
/resources
- возвращает все сохраненные ссылки из БД с последним статус-кодом ответа ресурса для каждой ссылки с пагинацией и фильтрацией.Пример запроса с квери-параметрами:
/resources?availability=true&id=1&domain_zone=org&page=1per_page=2
-
GET
/logs
- возвращает последние 50 строчек лог-файла (их количество настраивается в конфигурации системы и задается в секцииMAX_LOG_LINES
) -
DELETE
/resources/<resource_id: int>
- удалить обработанную ссылку
Точкой входа в приложение является entry.py
в корневой директории проекта. Приложение обернуто в docker-compose, как и в прошлый раз для поднятия используется makefile :) Для установки необходимых библиотек и применения миграций используется скрипт docker-entrypoint.sh
.
Для развертывания нужно выполнить следующие шаги:
-
Клонировать репозиторий:
git clone https://github.com/Dana299/hungergames_part2.git && cd hungergames_part2
-
Создать файл
.env
по образцу.envexample
и указать в нем все явки и пароли. -
Выполнить команду:
make build
Затем
make up
-
Для остановки контейнеров выполните:
make down
В докере селери таски почему то не отрабатывают вовсе. При локальном развертывании если выполнить две команды в разных терминалах celery -A main.make_celery worker -l info
и celery -A main.make_celery beat -l info
, то все отрабатывает корректно - и периодические задачи, и отложенная задача для обработки файла. Для наглядности можно задать в файле make_celery.py
, чтобы задача отрабатывала каждую минуту:
@celery.on_after_configure.connect
def setup_periodic_making_requests(sender: Celery, **kwargs):
"""Add periodic task for getting responses from all resources from DB and deleting unavailable ones."""
sender.add_periodic_task(
schedule=crontab(
minute="*",
),
sig=get_response_from_resources,
name="get_response_from_resources",
)
...
В Celery задаче для обработки ссылок из файла ответ никак не учитывает дубликаты ссылок (количество дублей в переданном файле и количество ссылок в файле, которые уже есть в бд). Также в идеале наверное стоит распределять обработку ссылок между разными воркерами celery.