Дикий Григорий

Full-stack веб-разработчик

Интернет-магазин на Django. Celery. Часть 7

Сегодня речь пойдет о Celery. Это замечательный продукт, который позволяет выполнять задачи асинхронно. К примеру, когда вы загрущаете видео на сервер вы не просто ждете пока оно не загрузится, а еще можете получить какие-то сообщения и все это происходит асинхронно.

Celery - это своего рода очередь задач, которая может использовать асинхронную передачу сообщений.

Первым делом установим Celery:

$ pip install celery==3.1.18

Для celery требуется менеджер сообщений для обработки сообщений. Для этих задач мы будем использовать RabbitMQ, так как она подходит лучше всего для выполнения этих задач. Мы настроим RabbitMQ на работу с Celery. Установим RabbitMQ:

$ sudo apt-get install rabbitmq-server

Добавим Celery в наш проект, для этого в директории myshop создадим файл celery.py со следующим содержимым:

import os
from celery import Celery
from django.conf import settings
# Основыне настройки Django для celery
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'myshop.settings')
app = Celery('myshop')
app.config_from_object('django.conf:settings')
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)

Таким образом Celery будет знать о нашем приложении через DJANGO_SETTINGS_MODULE. Поле этого мы создали экземпляр класса Celery для нашего приложения. После чего мы указали на файл конфигруции и наконец показали что для приложений из списка settings.INSTALLED_APPS

нужно выполнять асинхронные задачи.

Когда интерпретатор Python импортрирует папку впервые они запускает код файла __init__.py этого каталога. Поэтому давайте добавим код для импортирования нашего приложения. Для этого откроем файл __init__.py в папке myshop и добавим в него:

from .celery import app as celery_app

Теперь мы можем работать с асинхронными задачами в нашем онлайн-магазине. Добавим задачу по отправке сообщений если произошел заказ на сайте, для этого создайте в директории order файл tasks.py со следующим содержимым:

from celery import task
from django.core.mail import send_mail
from .models import Order
@task
def OrderCreated(order_id):
    """
    Отправка Email сообщения о создании покупке
    """
    order = Order.objects.get(id=order_id)
    subject = 'Заказ c номером {}'.format(order.id)
    message = 'Дорогой, {}, вы успешно сделали заказ.\
               Номер вашего заказа {}'.format(order.first_name, order.id)
    mail_send = send_mail(subject, message, 'admin@myshop.ru', [order.email])
    return mail_send

Мы использовали декоратор @task. Он будет отвечать за асинхронное выполнение задач, а это означает, что пользователь сможет во время отправки сообщения пользоваться сайтом. Добавим в файл settings.py из директории myshop следующее:

# Email
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

Этим самым наши emal сообщения не будут посылаться пользователю, а будут отображены в консоли. Теперь когда мы настроили эту задачу, ее надо включить в вьюху OrderCreate из директории order:

...
from .tasks import OrderCreated
def OrderCreate(request):
            ...
            cart.clear()
            
            # Асинхронная отправка сообщения
            OrderCreated.delay(order.id)
            ...

Теперь давайте запустим обработчик celery в командной строке. Для этого в нашу консоль напишем следующее:

$ celery -A myshop worker -l info

После этого мы можем добавить в нашу корзину пару вещей и сделать заказ, чтобы посмотреть как работает Celery. В итоге в консоли мы должны получить следующее:

[tasks]
  . orders.tasks.OrderCreated

Для того, чтобы управлять задачами Celery наглядно можно использовать Flower, который предоставит удобный веб интерфейс. Для его установки выполним команду в консоли:

$ pip install flower

И запустим celery следующим образом:

$ celery -A myshop flower

Имейте ввиду, что процесс выполнения worker'ов не должен быть прекращен. В итоге перейдя по адресу http://localhost:5555/dashboard вы должны наблюдать примерно следующее:

Репозиторий проекта: github

Текущий коммит: 859988434ed85e4380a9484c837e3756727c21a0