Pull to refresh

Асинхронные задания в Django c помощью Celery

Reading time 5 min
Views 65K
Приветствую!
Думаю, большинство разработчиков 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:

image

Если в качестве бэкенда celery использовать что-либо отличное от Django ORM (RabbitMQ например), то в админке Django можно было бы также просматривать состояние всех остальных заданий, выглядит примерно так:

image
Подробнее: 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.

Пара замечаний о производительности:

Подробнее об этих и других советах по Celery: http://celeryproject.org/docs/userguide/tasks.html#tips-and-best-practices
Tags:
Hubs:
+46
Comments 64
Comments Comments 64

Articles