Здравствуйте, друзья!
Порой встают задачи, когда нужно выполнять некоторые задания в фоновом режиме и получать результат их выполнения. Иногда задачи требуется распределять между серверами, но ещё чаще их необходимо ставить в очередь. Для этого, и много другого существует замечательный проект Celery. Он позволяет без особого труда превращать обычные функции в т.н. tasks.

Task — это задача, которую можно поставить в очередь на выполнение. Celery выдаст конкретному таску уникальный ID и как только место в очереди освободится — примется за его выполнение. После окончания работы задания его результат будет помещён в используемый бекенд.
Celery поддерживает несколько бекендов, включая RabbitMQ, Redis и даже базу данных.
RabbitMQ отлично подходит для этих целей — он относительно быстрый (написан на erland), легко конфигурируется, и главное — он даёт возможность гарантированного выполнения задания. Даже если предназначенный для выполнения таска сервер недоступен, как только он выйдет в online и запустит Celery сервис, RabbitMQ даст возможность узнать, какие задания он пропустил и Celery примется за их выполнение.
Бекенд MySQL удобен тем, что для него почти не нужно никаких серверных решений. Его легко запустить почти где угодно, где есть MySQL. Из минусов можно назвать не такую высокую скорость, как в случае с RabbitMQ.
Но бывают случае, когда производительность стоит на первом месте. RabbitMQ хранит базу данных на диске, как это делает и MySQL и при нескольких тысячах запросов подряд обычные SATA диски чувствуют себя не самым лучшим образом. Что же делать, если нужно ставить в очередь множество относительно небольших заданий, но которые не умещаются по времени в обычный http response?
Решение есть — хранить все данные, требуемые для работы Celery в оперативной памяти, самом быстром из мест хранения данных. Тем более одноименный продукт предоставляет для этого готовый бекенд.

Установка Redis в CentOS

В RPM-base дистрибутивах, к каким так же относится популярные RedHat и Fedora установка Redis происходит в 1 команду:
# yum install redis
Основной конфигурационный файл сервиса распологается в /etc/redis.conf, но для наших демонстрационных целей стандартных настроек вполне достаточно, так что запускаем сервис и добавляем его в автозагрузку:
# service redis start
# chkconfig redis on

Установка библиотек Python

Теперь выполним установку необходимого ПО через PIP. Его Вы используете Virtualenv, не забудьте войти в окружение

$ pip install redis celery celery-with-redis django-celery
После этих нехитрых действий всё готово для конфигурации проекта.

Конфигурация проекта

Теперь выполним настройку Django-проекта на использование Celery и Redis.
Конфигурация setings.py:
import djcelery # Импорт Django-celery модуля
djcelery.setup_loader()

# Celery settings
# Время, через которое хранимый в результат будет удалён: 5 часов
CELERY_TASK_RESULT_EXPIRES = 18000  
# Отправлять оповещение о проблемах выполнения тасков на E-mail (берутся адреса из settings.ADMINS)
CELERND_TASK_ERROR_EMAILS = True 
# Тип бекенда Celery для хранения результатов выполнения заданий
CELERY_RESULT_BACKEND = "redis" 
# Адрес Redis-сервера
CELERY_REDIS_HOST = "localhost" 
# Порт Redis-сервера
CELERY_REDIS_PORT = 6379 
# Нормер Redis Database
CELERY_REDIS_DB = 0 

# Broker settings
# Адрес броекра. Мы указываем протокол (redis://), адрес сервера (localost), порт (6379) и номер БД (0)
BROKER_URL = "redis://localhost:6379/0" 

Запуск Celery

Для простого запуска можно воспользоваться командой:
$ ./manage.py celeryd —concurrency=1 —loglevel=INFO
Таким образом мы запускам Celery с всего лишь одним максимально возможным конкурентным заданием в очереди и уровнем вывода INFO (подробнее о уровнял логирования можно прочитать тут).
На Production-сервер, конечно, такой способ не подходит и нужно что то более практичное. Есть 2 основных способа — использование init.d скрипта (мне этот способ больше по душе) и использование Supervisord для менеджмента данного процесса. Подробнее об этом описано в документации по деманизации Celery.

Проверка


В своём Django application разместите файл tasks.py. Именно его будет просматривать Celery при запуске и брать из него задания.
Создадим тестовое задание, что будет возвращать сумму переданых аргументов
from celery.decorators import task @task def my_task(a, b): return a + b Как видно из примера — мы импортировали декоратор celery.decorators.task. Он даёт возможность превратить обычную функцию my_task в задачу Celery.
Теперь перезапускаем Celery и заходим в Django Shell, импортируем наше задание и запускам его:
In [1]: from mailer.tasks import my_task

In [2]: result = my_task.delay(3, 5)

In [3]: result.task_id
Out[3]: '00ea6697-a848-439b-8c65-fb09662cd771'
Теперь проверим статус выполнения таска:
In [4]: result.status
Out[4]: 'SUCCESS'
Это значит, что задание выполнено. Получим результат:
In [5]: result.result
Out[5]: 8

Отлично. Всё прошло, как надо. Теперь можно выполнять тяжёлые задания и не думать, что пользователя будет нервировать долгий ответ от сервера :)

Источник: http://hosting4django.net/blog/python/django/celery-redis
18 Июнь 2012, 12:06 8 daniel
blog comments powered by Disqus