Python

Django, Celery и Redis

Spread the love

Эта небольшая статья предназначена для того, кто еще не знаком с Celery и не знает что это такое. В статье рассказывает как быстро запустить Celery вместе с Django, для выполнения асинхронных задач которые будут выполнятся отдельно от процесса Django. Классическим примером такой задачи может быть отправка email (мы ее рассмотрим ниже). Хотя это может быть любая задача вся обработка которой должна происходит отдельно от запроса пользователя. Еще один распространенным примером может быть загрузка и последующая конвертация медиа файлов.

Базовая документация по настройке Celery с Django находится тут

Итак для начало создадим новую директорию с каким-нибудь названием типа temp:

mkdir temp
cd temp

Далее создадим виртуальное окружение с помощью pipenv c python 3.6 При установке python 3.7 возможно появление проблемы запуска Celery beat описанная тут

pipenv --python 3.6
pipenv shell

Далее установим Django и Celery. В качестве базы данных для Celery мы будем использовать Redis, поэтому так же установим поддержку Redis для Celery

pipenv install django
pipenv install celery
pipenv install celery[redis]

Теперь создадим наш проект на Django и сразу запустим миграцию базы по умолчанию.

django-admin startproject testapp
...
cd testapp
python manage.py migrate

Создадим новое приложение в Django и папку для шаблонов.

django-admin startapp home
mkdir templates

После его создания подключим его в INSTALLED_APPS, настроим папку шаблонов

testapp/settings.py

...
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'home'
]
...

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        ....
    },
]
...
BROKER_URL = 'redis://127.0.0.1:6379/0'
BROKER_TRANSPORT = 'redis'
...

Далее создадим файл index.html с дефолной версткой

templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
 <h1>Hello world</h1>
</body>
</html>

Создадим новый файл Celery testapp/celery.py

import os
import django

from celery import Celery
from django.conf import settings

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'testapp.settings')
django.setup()

app = Celery('testapp')

app.config_from_object('django.conf:settings')
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)

Создадим файл задач testapp/tasks.py

from time import sleep
from testapp.celery import app

@app.task
def hello_world():
  sleep(10) # поставим тут задержку в 10 сек для демонстрации ассинхрности
  print('Hello World')
  

Создадим вьюху по умолчанию для обработки запроса home/views.py

from django.shortcuts import render
from django.views.generic import TemplateView

from testapp.tasks import hello_world

class IndexView(TemplateView):
  template_name = 'index.html'

  def get_context_data(self, **kwargs):
    context = super(IndexView, self).get_context_data(**kwargs)
    hello_world()
    return context

Сейчас само время проверить как это работает. Запустим сервер Django

python manage.py runserver

И зайдем в браузере по адресу http://127.0.0.1:8000 то через 10 секунд мы должны увидеть ответ от сервера.

В консоли мы должны увидеть что то типа следующего

Обратите внимание на Hello world. Наша тестовая задача была выполнена после 10 сек от получения запроса.

Теперь попробуем запустить нашу задачу через Celery. Для этого отредактируйте файл home/views.py что бы додавить в него hello_world.delay()

  def get_context_data(self, **kwargs):
    context = super(IndexView, self).get_context_data(**kwargs)
    hello_world.delay()
    return context

Убедитесь что у вас запущен сервер Redis

redis-server

Так же теперь нам нужно запустит Celery. Для этого в новом окне терминала войдем в наше виртуальное окружение и выполним команду запуска Celery

pipenv shell
celery worker -A testapp -l debug

Теперь можно снова зайти на http://127.0.0.1:8000 и мы сразу получим ответ от сервера, а через 10 секунд можно будет увидеть в консоле выполнение нашей задачи.

Асинхронная отправка Email

Внесем настройки email в Django в файл testpp/settings.py

...
EMAIL_HOST = 'XXXX'
EMAIL_PORT = '465'
EMAIL_HOST_USER = 'XXXX' 
EMAIL_HOST_PASSWORD = 'XXXX'
EMAIL_USE_TLS = False
EMAIL_USE_SSL = True
...

Далее создадим задачу для отправки email. Для этого в файл testapp/tasks.py внесем следующее:

from time import sleep
from django.core.mail import send_mail

@app.task
def send_email_task():
  # сделаем задержку на 10 сек для демонстрации ассинхроности
  sleep(10) 
  send_mail('Тема письма', 'Тело письма', 'адрес_отправителя@mail.com', ['адрес_получателя@mail.com'])

Далее вызовем эту задачу в нашей вьюхе home/views.py:

...
def get_context_data(self, **kwargs):
    context = super(IndexView, self).get_context_data(**kwargs)
    send_email_task.delay()
    return context

Все этого достаточно. Теперь при обращение к http://127.0.0.1:8000 от сервера будет сразу получен ответ, а через 10 сек по указанному адресу будет отправлено письмо.

Celery beat

Работа Celery в режиме beat заключается в том, чтобы запускать задачи Celery в соответствии с расписанием. Допустим у нас есть задача которую необходимо запускать по расписанию, например нам нужно чистить какую нибудь папку каждые 5 минут.

Внесем наше расписание в testapp/celery.py Время запуска устанавливается через crontab.

...
from celery.schedules import crontab
...

app.conf.beat_schedule = {
    'run-every-single-minute': {
        'task': 'testapp.tasks.hello_world',
        'schedule': crontab(),
    },
}

Далее нам потребуется запустить в еще одном терминальном окне Celery в режиме beat

celery -A testapp beat -l debug

Заключение

Надеюсь это небольшая статья помогла вам быстро разобраться с настройка Celery для Django. Если у вас остались вопросы пишите их в комментариях.

Была ли вам полезна эта статья?
[10 / 3.4]

Spread the love
DenSP

View Comments

  • Добрый день ! Как запустить celery на web хостинге от reg.ru??

Recent Posts

Vue 3.4 Новая механика v-model компонента

Краткий перевод: https://vuejs.org/guide/components/v-model.html Основное использование​ v-model используется для реализации двусторонней привязки в компоненте. Начиная с Vue…

12 месяцев ago

Анонс Vue 3.4

Сегодня мы рады объявить о выпуске Vue 3.4 «🏀 Slam Dunk»! Этот выпуск включает в…

12 месяцев ago

Как принудительно пере-отобразить (re-render) компонент Vue

Vue.js — это универсальный и адаптируемый фреймворк. Благодаря своей отличительной архитектуре и системе реактивности Vue…

2 года ago

Проблемы с установкой сертификата на nginix

Недавно, у меня истек сертификат и пришлось заказывать новый и затем устанавливать на хостинг с…

2 года ago

Введение в JavaScript Temporal API

Каким бы ни было ваше мнение о JavaScript, но всем известно, что работа с датами…

2 года ago

Когда и как выбирать между медиа запросами и контейнерными запросами

Все, кто следит за последними событиями в мире адаптивного дизайна, согласятся, что введение контейнерных запросов…

2 года ago