Django 43. Подключаем Celery и Redis для фоновой отправки почты
В этом посте мы добавим поддержку Celery и Redis в наш Django-проект, чтобы отправлять электронную почту в фоновом режиме.
Дополнительные материалы
Для скачивания материалов необходимо войти или зарегистрироваться
Файлы также можно получить в Telegram-боте по коду: 336244
Реклама
В синхронном программировании, которое используется во фреймворке Django, все действия выполняются последовательно: следующая команда начинает выполняться только после полного завершения предыдущей. В посте "Django 39. Капча и подтверждение регистрации по email" мы добавили отправку письма на электронную почту для подтверждения регистрации. В данный момент это является "узким" местом по производительности, доставляя пользователю дискомфорт из-за ожидания завершения отправки формы регистрации.
Для решения этой проблемы мы воспользуемся инструментом Celery. Celery — это асинхронный менеджер задач. Он выполняет задачи в фоновом режиме в отдельном процессе, что позволяет не нагружать основной процесс тяжёлыми операциями. Для взаимодействия между основным приложением (в нашем случае Django) и отдельным процессом "работника Celery" (Celery worker), Celery использует СУБД Redis или менеджер очередей RabbitMQ. Мы будем использовать Redis, так как он проще для новичков, а про RabbitMQ поговорим в другой раз.
Redis — это популярная СУБД типа "ключ-значение". Проще говоря, Redis хранит записи в виде JSON. Благодаря тому, что вся база данных загружена в оперативную память, Redis обеспечивает высокую скорость работы с данными.
В этом посте мы добавим поддержку Celery и Redis в наш Django-проект, чтобы отправлять электронную почту в фоновом режиме.
Пост является продолжением поста "Docker 8. Разворачивание Django-проекта в Docker compose", так как для Celery и Redis будем использовать Docker.
Запускаем Redis.
Первым делом необходимо запустить Redis. Для этого откроем docker-compose.yaml
и добавим сервис redis
со следующим содержимым:
redis:
image: redis
restart: always
volumes:
- ./redis-data:/data
Конфигурация порта
Новых параметров здесь нет, однако стоит отметить один момент. Если вы разрабатываете локально и хотите проверять работу Celery, то необходимо указать ключ ports
:
ports:
- "6379:6379"
На VPS открывать порты сервисов "наружу" крайне нежелательно. Однако, если разработка ведётся локально вне Docker-контейнеров с самим Django-проектом, то следует либо установить Redis в систему, либо запустить контейнер с ним и указать порт, который будет доступен на вашей локальной машине.
Конфигурация переменных окружения
После того, как определили сервис для Redis, откройте .env
файл Django-проекта и добавьте новую переменную окружения:
# Если используется первый вариант в связке всего Docker compose:
REDIS_URL=redis://redis:6379/0
# Если Redis используется локально:
REDIS_URL=redis://localhost:6379/0
Разберём URL-адрес подключения к Redis на примере варианта с паролем:
redis://
— Протокол для подключения.адрес_сервера:6379
— Хост Redis-сервера и открытый порт./0
— Номер используемой базы данных, по умолчанию доступно от 0 до 15.
Установка зависимости Redis
Последним шагом в подготовке Redis будет установка Python-библиотеки. Выполним команду:
pip install redis
И обязательно добавим его в requirements.txt
:
redis==5.0.5
Подключение Celery к Django.
Для подключения Celery к Django выполним несколько шагов.
Установка зависимостей.
Первым шагом будет установка Python-библиотеки Celery. Для этого выполним команду:
pip install celery
Также сразу добавим её в requirements.txt
:
celery==5.4.0
Параметры Celery.
Откроем файл settings.py
Django-проекта. Необходимо добавить два параметра:
CELERY_BROKER_URL
— URL для подключения к брокеру сообщений. В нашем случае это Redis. Когда Celery получает задачу, она отправит необходимые для рабочего (Celery worker) данные в Redis. После этого рабочий увидит новую задачу и начнёт её выполнение в отдельном процессе.CELERY_RESULT_BACKEND
— URL для подключения к брокеру сообщений, указывающий Celery, куда отправлять результаты выполнения задач.
Обычно эти два параметра содержат идентичный путь, но всё зависит от потребностей и реализации. Возможно, вам потребуется получать результаты выполнения в другую Redis-БД.
Добавим эти параметры в settings.py
:
CELERY_BROKER_URL = os.environ.get("REDIS_URL")
CELERY_RESULT_BACKEND = os.environ.get("REDIS_URL")
Создание файла Celery-приложения
Для запуска Celery определим его точку входа. В директории Django-проекта рядом с файлом settings.py
создадим файл celery.py
.
В этом файле определим Celery-приложение, укажем настройки Django и включим автоматический поиск задач:
import os
from celery import Celery
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "pressanybutton.settings")
app = Celery("pressanybutton")
app.config_from_object("django.conf:settings", namespace='CELERY')
app.autodiscover_tasks()
Разберём код:
- Импортируем модуль
os
из стандартной библиотеки Python и классCelery
из библиотекиcelery
. - Устанавливаем переменную окружения
DJANGO_SETTINGS_MODULE
, если она ещё не установлена. Эта переменная указывает на модуль настроек Django, обычно в формеproject_name.settings
. В данном случае этоpressanybutton.settings
. Это нужно, чтобы Celery знал, где искать настройки Django. - Объявляем экземпляр класса
Celery
, передав в него имя для идентификации проекта. - Конфигурируем объект
Celery
использовать настройки из объектаsettings
модуляdjango.conf
. Опцияnamespace='CELERY'
означает, что Celery будет искать только те настройки, которые начинаются с префиксаCELERY_
, например,CELERY_BROKER_URL
. - Последняя строка указывает объекту
Celery
автоматически обнаруживать и загружать задачи из установленных приложений Django. Celery будет искать модульtasks.py
в каждом установленном приложении.
Видимость Celery-приложения.
Для того чтобы Celery-приложение инициализировалось при запуске Django, необходимо обеспечить его видимость в проекте. Для этого откроем файл __init__.py
в директории с проектом, где находятся файлы celery.py
и settings.py
, и добавим следующие строки:
from .celery import app as celery_app
__all__ = ('celery_app',)
Разберём код:
- Импорт Celery-приложения: В первой строке мы импортируем экземпляр класса
Celery
, который определён в переменнойapp
в файлеcelery.py
. - Экспорт Celery-приложения: Во второй строке мы экспортируем импортированный объект
app
какcelery_app
. Это делается для того, чтобы Celery-приложение было доступно как модуль при импорте из других частей проекта.
Этот шаг гарантирует, что Celery-приложение будет инициализировано и готово к использованию всякий раз, когда Django-приложение запускается.
Запуск Celery локально.
Во время разработки желательно всё проверять до загрузки на VPS. В этом блоке рассмотрим, как запускать Celery локально.
Для работы Celery необходим Redis. Убедитесь, что Redis запущен локально или удалённо и доступен для подключения.
Запуск Django и Celery
Откройте два терминала в директории проекта:
В первом терминале запустите Django:
python manage.py runserver
Во втором терминале для запуска Celery выполните следующую команду:
celery -A pressanybutton.celery worker -l INFO
Для пользователей Windows
Возможны проблемы с запуском Celery на Windows. В этом случае используйте команду:
celery -A pressanybutton.celery worker -l INFO -P solo
Разберём команду:
celery
- Запуск процесса приложения Celery.-A pressanybutton.celery
- Указание на использование рабочего модуля. В нашем случае это файлcelery.py
.worker
- Указание на то, что необходимо запустить рабочий процесс (Celery worker).-l INFO
- Уровень логирования. УровеньINFO
выводит в консоль информационные сообщения о выполняемых процессах, помимо более серьёзных уровней логирования. Можно изменить на один из:INFO
,DEBUG
,WARNING
,ERROR
иCRITICAL
.-P solo
- Актуально для пользователей Windows. Указывает на количество Celery-процессов. Параметрsolo
означает, что будет запущен только один процесс Celery.
Celery worker в Docker compose.
Поскольку Celery требует запуска в отдельном от Django-процессе, для его работы в Docker compose мы создадим новый сервис worker
. Этот worker
по сути будет копией контейнера с Django-проектом, но с отличием в команде запуска.
Настройка Docker compose
Откроем файл docker-compose.yaml
и добавим новый ключ worker
со следующим содержимым:
worker:
build: ./pressanybutton
command: celery -A pressanybutton.celery worker -l INFO
env_file:
- ./pressanybutton/.env
volumes:
- ./pressanybutton:/code
depends_on:
- web
- redis
- db
Пояснение конфигурации
Обратим внимание на ключевые параметры:
build: ./pressanybutton
- Указывает путь к директории с проектом для сборки Docker-образа.command: celery -A pressanybutton.celery worker -l INFO
- Команда запуска рабочего Celery.env_file: - ./pressanybutton/.env
- Подключение файла окружения с переменными.volumes: - ./pressanybutton:/code
- Примонтирование директории проекта.depends_on: - web, - redis, - db
- Определение зависимостей: рабочий процесс Celery зависит от сервисовweb
(Django-проект),redis
, иdb
.
Заключение.
Мы познакомились с Celery и Redis, подготовили Django для работы с Celery и запустили Celery worker.
Celery – это мощный и полезный инструмент для выполнения фоновых задач. С его помощью можно обрабатывать множество различных задач, не только в рамках Django. Примеры таких задач включают:
- Формирование отчётов: Сбор данных, их анализ и генерация отчётов без задержки основной функциональности приложения.
- Обработка данных: Выполнение ресурсоёмких операций, таких, как преобразование и очистка данных, агрегация и другие виды обработки.
- Обработка изображений: Манипуляции с изображениями, такие, как изменение размера, применение фильтров или создание эскизов.
- Отправка электронной почты: Автоматическая отправка писем, создание рассылок и уведомлений пользователям.
- Периодические задачи: Выполнение задач по расписанию, например, очистка временных файлов, резервное копирование данных или синхронизация с внешними сервисами.
Использование Celery позволяет значительно разгрузить основной процесс приложения, улучшая его производительность и отзывчивость для пользователей.
В следующем посте мы рассмотрим, как настроить и использовать Celery для отправки электронной почты в фоновом режиме.
Все статьи