Asynchroniczne zadania - Celery w projektach Django
Celery to asynchroniczna kolejka zadań zlecanych przez np. aplikacje webowe. Zadania mogą być wykonywane asynchronicznie - aplikacja zlecająca nie czeka na wynik, lub synchronicznie - z oczekiwaniem na wynik. Zadania wykonywane mogą być współbieżnie na jednym lub wielu serwerach. Cały ten system ma już za sobą liczne udane wdrożenia, a jego główne zadanie to odciążanie aplikacji webowych od wykonywania długotrwałych operacji związanych z jakąś akcją (np. generowanie miniatur, wysyłanie żądań do zewnętrznych API itd.).
Dostępne są także integracje z popularnymi frameworkami, np. django-celery, celery-pylons, czy flask-celery.
Instalacja Celery i zależności
Celery można zainstalować poprzez pip lub easy_install:pip install Celery easy_install Celery pip install django-celery easy_install django-celery
Integracja z Django
Django-celery zapewnia nam integrację z frameworkiem Django. Po instalacji pakietu musimy skonfigurować projekt Django. Do INSTALLED_APPS dodajemy "djcelery", oraz:import djcelery
djcelery.setup_loader()
BROKER_HOST = "127.0.0.1"
BROKER_PORT = 5672
BROKER_VHOST = "/"
BROKER_USER = "guest"
BROKER_PASSWORD = "guest"
import os
os.environ["CELERY_LOADER"] = "django"
Tworzenie zadań dla Celery
Zadania dla Celery w aplikacji Django powinny znajdować się w pliku tasks.py. Szkielet zadania (Task) wygląda następująco:from celery.decorators import task
@task()
def add(x, y):
return x + y
from moja_aplikacja.tasks import NazwaZadania
NazwaZadania.delay(some_arg="foo")
W konsoli z działającym Celery powinniśmy widzieć napływające zadania do wykonania. Notka: jeżeli dodałeś lub zmodyfikowałeś jakieś zadanie to zrestartuj Celery (manage.py celeryd) by zmiany zostały zauważone.
Powyższy kod szkieletowy już działa, lecz Celery oferuje tonę opcji i możliwości. Dokładny opis znajdziemy w dokumentacji, a różne gotowe rozwiązania na blogach, czy w prezentacjach. Dla przykładu warto zadbać o odpowiednie logi z wykonywanego zadania (szczególnie gdy jest złożone). Można zrobić to tak:@task
def FooBarTask():
"""
Just a showcase task for Celery :)
"""
logger = FooBarTask.get_logger()
logger.info('Starting FooBarTask')
loop = 1
while loop < 10000000:
loop += 1
logger.info('Finished FooBarTask')
[2011-12-30 10:19:38,425: INFO/MainProcess] Got task from broker: myapp.tasks.FooBarTask[0709d0cf-01cb-47e1-b7a3-ba1164bd4e84] [2011-12-30 10:19:38,444: INFO/PoolWorker-3] myapp.tasks.FooBarTask[0709d0cf-01cb-47e1-b7a3-ba1164bd4e84]: Starting FooBarTask [2011-12-30 10:19:38,900: INFO/PoolWorker-3] myapp.tasks.FooBarTask[0709d0cf-01cb-47e1-b7a3-ba1164bd4e84]: Finished FooBarTask [2011-12-30 10:19:38,969: INFO/MainProcess] Task myapp.tasks.FooBarTask[0709d0cf-01cb-47e1-b7a3-ba1164bd4e84] succeeded in 0.525212049484s: None
I to by było na tyle z podstaw Celery :)
Comment article