Celery 先前的版本需要額外安裝一個庫才能與 Django 集成,但是自3.1版本開始,再也不需要了。現在 Celery 直接支持 Django 了,本文提供一個比較基本的方法將 Celery 集成到 Django 項目中。你將使用與非 Django 用戶同樣的API,所以在閱讀本文之前最好看一下Celery 初步。當你完成一個可以正常運行的例子后,再看看Celery 進階。
為了在 Django 項目中使用 Celery,必須先定義一個 Celery 實例(也叫做 app)。
假如 Django 項目布局是這樣的:
- proj/
- proj/__init__.py
- proj/settings.py
- proj/urls.py
- manage.py
那么,推薦的做法是創建一個新的 proj/proj/celery.py 模塊,然后在這個模塊中定義 Celery 實例。
file: proj/proj/celery.py
from __future__ import absolute_import
import os
from celery import Celery
from django.conf import settings
# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proj.settings')
app = Celery('proj')
# Using a string here means the worker will not have to
# pickle the object when using Windows.
app.config_from_object('django.conf:settings')
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
@app.task(bind=True)
def debug_task(self):
print('Request: {0!r}'.format(self.request))
接著,需要在 proj/proj/__init__.py 模塊中導入這個 Celery 實例(也就是 app)。這樣可以確保當 Django 啟動時可以加載這個 app,并且 @shared_task 裝飾器(后面會提到)也能使用這個 app.
file: proj/proj/__init__.py
from __future__ import absolute_import
# This will make sure the app is always imported when
# Django starts so that shared_task will use this app.
from .celery import app as celery_app
需要注意的是,上述項目布局示例適合大型項目。對于簡單的項目,你可以在一個模塊中同時定義 Celery 實例和任務,就像Celery 初步里面那樣。
我們看看在 proj/proj/celery.py 模塊中到底做了什么事。首先,從 future 模塊導入 absolute_import,這樣,celery.py 模塊就不會與 Celery 庫相沖突:
from __future__ import absolute_import
然后,為 celery 命令行程序設置環境變量 DJANGO_SETTINGS_MODULE 的默認值:
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proj.settings')
設置這個環境變量是為了讓 celery 命令能找到 Django 項目。這條語句必須出現在 Celery 實例創建之前,也就是接下來要做的:
app = Celery('proj')
這個 app 就是 Celery 實例。可以有很多 Celery 實例,但是當使用 Django 時,似乎沒有必要。
我們也將 Django settings 模塊作為 Celery 的配置來源。也就是說,不需要使用多個配置文件,直接在 Django settings 里面配置 Celery.
可以將 settings 對象作為參數傳入,但是更好的方式是使用字符串,因為當使用 Windows 系統或者 execv 時 celery worker 不需要序列化 settings 對象:
app.config_from_object('django.conf:settings')
為了重用 Django APP,通常是在單獨的 tasks.py 模塊中定義所有任務。Celery 會自動發現這些模塊:
app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)
加上上一句后,Celery 會自動發現 Django APP 中定義的任務,前提是遵循如下 tasks.py 約定:
- app1/
- tasks.py
- models.py
- app2/
- tasks.py
- models.py
這樣就不需要手動把一個個模塊加到 CELERY_IMPORTS 配置中。傳入的 lambda 函數有如下好處:只在需要的時候才自動發現任務,以及當導入模塊時不需要立即對 settings 對象求值。
最后,debug_task 是一個打印本身 request 信息的任務。它使用了在 Celery 3.1引入的任務選項 bind=True,使得引用當前任務實例變得很容易。
使用 @shared_task 裝飾器
你很可能在可重用的 Django APP 中編寫了一些任務,但是 Django APP 不能依賴于具體的 Django 項目,所以你無法直接導入 Celery 實例。
@shared_task 裝飾器能讓你在沒有具體的 Celery 實例時創建任務:
file: demoapp/tasks.py:
from __future__ import absolute_import
from celery import shared_task
@shared_task
def add(x, y):
return x + y
@shared_task
def mul(x, y):
return x * y
@shared_task
def xsum(numbers):
return sum(numbers)
另請參閱
你可以在這里找到這個 Django 示例項目的完整源碼。
使用 Django ORM/Cache 作為結果存儲后端(result backend)
如果想在 Django 數據庫中保存任務執行結果,還需要安裝 django-celery 庫(或者使用 SQLAlchemy 結果存儲后端)。
django-celery 庫基于 Django ORM和緩存框架實現了結果存儲后端.
為了在項目中使用該擴展,遵循如下四步:
-
安裝 django-celery 庫
<pre class=”brush: bash; gutter: false;”>
$ pip install django-celery
</pre> 把 djcelery 加到 INSTALLED_APPS 中
-
創建 celery 用到的數據庫表
當使用數據庫作為結果存儲后端時,這一步會創建用來保存任務結果的相關數據庫表,以及周期任務調度器需要使用的數據庫表。如果不使用周期任務和任務結果,可以跳過這一步。
如果使用 south 來做模式遷移,執行:
<pre class=”brush: bash; gutter: false;”>
$ python manage.py migrate djcelery
</pre>如果不使用 south,執行:
<pre class=”brush: bash; gutter: false;”>
$ python manage.py syncdb
</pre> -
配置 celery 使用 django-celery 結果存儲后端
對于數據庫后端,使用:
<pre class=”brush: python; gutter: false;”>
app.conf.update(
CELERY_RESULT_BACKEND='djcelery.backends.database:DatabaseBackend',
)
</pre>對于緩存后端,使用:
<pre class=”brush: python; gutter: false;”>
app.conf.update(
CELERY_RESULT_BACKEND='djcelery.backends.cache:CacheBackend',
)
</pre>如果你將 Django settings 作為 Celery 的配置來源,可以直接在 settings 模塊中加上 CELERY_RESULT_BACKEND 配置項,不需要 app.conf.update
相對導入
在導入任務模塊時,必須保持一致性。也就是說,如果在 INSTALLED_APPS 中添加的是 project.app,那么需要以 from project.app 的方式導入任務,否則任務的名稱將會不一樣。
參見自動命名與相對導入。
啟動 worker 進程
在生產環境中,你希望在后臺以守護進程的方式運行 worker(參見以守護進程運行 worker),但是在測試開發環境中,像 Django 的 runserver 那樣使用 celery worker 管理命令來啟動一個 worker 實例,就有用多了:
$ celery worker -A proj -l info
要查看 celery 的完整命令行選項,使用 help 命令:
$ celery help