Приветствую!
Думаю, большинство разработчиков Django слышали о Celery — системе асинхронного выполнения заданий, а многие даже активно её используют.
Около года назад на хабре была довольная хорошая статья, рассказывающая о том, как использовать Celery. Однако, как было упомянуто в заключении, уже вышла Сelery 2.0 (на данный момент стабильной версией является 2.2.7), где интеграция с django была вынесена в отдельный пакет, а также произошли другие изменения.
Данная статья будет полезна прежде всего новичкам, которые начинают работать с Django, и им требутся что-то, способное выполнять асинхронные и/или периодические задания в системе (например очистку устаревших сессий). Я покажу как установить и настроить Сelery для работы с Django от начала до конца, а также расскажу про некоторые другие полезные настройки и подводные камни.
Прежде всего проверим наличие в системе пакета python-setuptools, и установим его в случае отсутствия:
Подробнее в оригинале: http://celeryq.org/docs/getting-started/introduction.html#installation
В статье, ссылка на которую дана в начале, в качестве бэкенда использовалась MongoDB, здесь я покажу как в качестве бэкенда и брокера сообщений использовать ту же самую БД, в которой хранят данные остальные приложения Django.
Как уже было сказано, django-celery предоставляет удобную интеграцию Celery и Django. В частности он использует Django ORM как бэкенд для сохранения результатов выполнения заданий Celery, а также автоматически находит и регистрирует задания Celery для приложений Django, перечисленных в INSTALLED_APPS.
После установки django-celery нужно сконфигурировать:
При использовании mod_wsgi добавить следующие строки в конфигруационный файл WSGI:
Устанавливаем пакет:
Настраиваем:
(Без celerybeat можно запускать и выполнять обычные (regular) задания. Для выполнения периодических заданий по расписанию необходим запуск celerybeat)
После запуска можем посмотреть как выглядят периодические задания в админке django:
Если в качестве бэкенда celery использовать что-либо отличное от Django ORM (RabbitMQ например), то в админке Django можно было бы также просматривать состояние всех остальных заданий, выглядит примерно так:
Подробнее: http://stackoverflow.com/questions/5449163/django-celery-admin-interface-showing-zero-tasks-workers
UPDATE: дописываю немного про демонизацию, так как может получиться не с первого раза.
В каталоге /etc/default создаём файл celeryd, из него скрипт будет брать настройки запуска:
Опция --concurrency задаёт число процессов celery (по умолчанию это число равно количеству процессоров).
После этого можно запустить celery с помощью service:
Подробнее: docs.celeryproject.org/en/latest/tutorials/daemonizing.html#daemonizing
Также полезно активировать опцию CELERY_SEND_TASK_ERROR_EMAILS, благодаря который Celery будет уведомлять обо всех ошибках по адресам, перечисленным в переменной ADMINS.
Написание заданий для celery практически не изменилось со времён предыдущей статьи:
Единственное отличие — декораторы теперь следует импортировать из celery.task, модуль decorators стал deprecated.
Пара замечаний о производительности:
Подробнее об этих и других советах по Celery: http://celeryproject.org/docs/userguide/tasks.html#tips-and-best-practices
Думаю, большинство разработчиков Django слышали о Celery — системе асинхронного выполнения заданий, а многие даже активно её используют.
Около года назад на хабре была довольная хорошая статья, рассказывающая о том, как использовать Celery. Однако, как было упомянуто в заключении, уже вышла Сelery 2.0 (на данный момент стабильной версией является 2.2.7), где интеграция с django была вынесена в отдельный пакет, а также произошли другие изменения.
Данная статья будет полезна прежде всего новичкам, которые начинают работать с Django, и им требутся что-то, способное выполнять асинхронные и/или периодические задания в системе (например очистку устаревших сессий). Я покажу как установить и настроить Сelery для работы с Django от начала до конца, а также расскажу про некоторые другие полезные настройки и подводные камни.
Прежде всего проверим наличие в системе пакета python-setuptools, и установим его в случае отсутствия:
aptitude install python-setuptools
Установка Celery
Сама Celery устанавливается очень просто:
easy_install Celery
Подробнее в оригинале: http://celeryq.org/docs/getting-started/introduction.html#installation
В статье, ссылка на которую дана в начале, в качестве бэкенда использовалась MongoDB, здесь я покажу как в качестве бэкенда и брокера сообщений использовать ту же самую БД, в которой хранят данные остальные приложения Django.
django-celery
Устанавливаем пакет django-celery:
easy_install django-celery
Как уже было сказано, django-celery предоставляет удобную интеграцию Celery и Django. В частности он использует Django ORM как бэкенд для сохранения результатов выполнения заданий Celery, а также автоматически находит и регистрирует задания Celery для приложений Django, перечисленных в INSTALLED_APPS.
После установки django-celery нужно сконфигурировать:
- добавить djcelery в список INSTALLED_APPS:
INSTALLED_APPS += ("djcelery", )
- добавить следующие строки в файл настроек django {{settings.py}}:
import djcelery djcelery.setup_loader()
- Создать необходимые таблицы в БД:
./manage.py syncdb
- Задаём БД в качестве места хранения периодических заданий, добавляем в settings.py:
CELERYBEAT_SCHEDULER = "djcelery.schedulers.DatabaseScheduler"
С помощью этой опции мы сможем добавлять/удалять/редактировать периодические задания через админку django.
При использовании mod_wsgi добавить следующие строки в конфигруационный файл WSGI:
import os
os.environ["CELERY_LOADER"] = "django"
django-kombu
Теперь нам осталось найти подходящего брокера сообщений (message broker) для Celery, в этой статье я буду использовать django-kombu — пакет, позволяющий использовать базу данных Django в качестве хранилища сообщений (message store) для Kombu (реализация AMPQ на питоне).Устанавливаем пакет:
easy_install django-kombu
Настраиваем:
- добавляем djkombu в список INSTALLED_APPS:
INSTALLED_APPS += ("djkombu", )
- Задаём djkombu в качестве брокера в settings.py:
BROKER_BACKEND = "djkombu.transport.DatabaseTransport"
- Создаём необходимые таблицы в БД:
./manage.py syncdb
Запускаем
Запускаем процессы celery и celerybeat:(Без celerybeat можно запускать и выполнять обычные (regular) задания. Для выполнения периодических заданий по расписанию необходим запуск celerybeat)
- В linux оба процесса можно запустить одновременно с помощью ключа -B:
# ./manage.py celeryd -B -------------- celery@test v2.2.7 ---- **** ----- --- * *** * -- [Configuration] -- * - **** --- . broker: djkombu.transport.DatabaseTransport://guest@localhost0/ - ** ---------- . loader: djcelery.loaders.DjangoLoader - ** ---------- . logfile: [stderr]@WARNING - ** ---------- . concurrency: 16 - ** ---------- . events: OFF - *** --- * --- . beat: ON -- ******* ---- --- ***** ----- [Queues] -------------- . celery: exchange:celery (direct) binding:celery
- В windows celery и celerybeat необходимо запускать отдельно:
./manage.py celeryd --settings=settings ./manage.py celerybeat
Опция --settings может потребоваться, если возникает следующее исключение:
ImportError: Could not import settings 'app_name.settings' (Is it on sys.path?): No module named app_name.settings
Подробнее о проблеме: http://groups.google.com/group/celery-users/browse_thread/thread/43a95be6865a636/d91ab2492885f3d4?lnk=gst&q=settings#d91ab2492885f3d4
Полный список известных проблем с celery на Windows: http://celeryproject.org/docs/faq.html#windows
После запуска можем посмотреть как выглядят периодические задания в админке django:
Если в качестве бэкенда celery использовать что-либо отличное от Django ORM (RabbitMQ например), то в админке Django можно было бы также просматривать состояние всех остальных заданий, выглядит примерно так:
Подробнее: http://stackoverflow.com/questions/5449163/django-celery-admin-interface-showing-zero-tasks-workers
UPDATE: дописываю немного про демонизацию, так как может получиться не с первого раза.
Запускаем celery в виде сервиса
Скачиваем скрипт запуска celery отсюда: https://github.com/ask/celery/tree/master/contrib/generic-init.d/ и помещаем его в каталог /etc/init.d с соответствующими правами.В каталоге /etc/default создаём файл celeryd, из него скрипт будет брать настройки запуска:
# Where the Django project is.
CELERYD_CHDIR="/var/www/myproject"
# Path to celeryd
CELERYD_MULTI="$CELERYD_CHDIR/manage.py celeryd_multi"
CELERYD_OPTS="--time-limit=300 --concurrency=8 -B"
CELERYD_LOG_FILE=/var/log/celery/%n.log
# Path to celerybeat
CELERYBEAT="$CELERYD_CHDIR/manage.py celerybeat"
CELERYBEAT_LOG_FILE="/var/log/celery/beat.log"
CELERYBEAT_PID_FILE="/var/run/celery/beat.pid"
CELERY_CONFIG_MODULE="settings"
export DJANGO_SETTINGS_MODULE="settings"
Опция --concurrency задаёт число процессов celery (по умолчанию это число равно количеству процессоров).
После этого можно запустить celery с помощью service:
service celeryd start
Подробнее: docs.celeryproject.org/en/latest/tutorials/daemonizing.html#daemonizing
Работа с celery
После установки django-celery задания celery регистрируются автоматически из всех модулей tasks.py из всех приложений, перечисленных в INSTALLED_APPS. Помимо модулей tasks можно также задать дополнительные модули с помощью параметра CELERY_IMPORTS:CELERY_IMPORTS=('myapp.my_task_module',)
Также полезно активировать опцию CELERY_SEND_TASK_ERROR_EMAILS, благодаря который Celery будет уведомлять обо всех ошибках по адресам, перечисленным в переменной ADMINS.
Написание заданий для celery практически не изменилось со времён предыдущей статьи:
from celery.task import periodic_task
from celery.schedules import crontab
@periodic_task(ignore_result=True, run_every=crontab(hour=0, minute=0))
def clean_sessions():
Session.objects.filter(expire_date__lt=datetime.now()).delete()
Единственное отличие — декораторы теперь следует импортировать из celery.task, модуль decorators стал deprecated.
Пара замечаний о производительности:
- Если задание не возвращает никакого резузьтата, то лучше установить опцию ignore_result=True
- Выключить ограничение скорости выполнения заданий (Rate limits), если ваши задания не используют их:
CELERY_DISABLE_RATE_LIMITS = True
Подробнее об этих и других советах по Celery: http://celeryproject.org/docs/userguide/tasks.html#tips-and-best-practices