在 Django 項目中使用 Celery

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和緩存框架實現了結果存儲后端.

為了在項目中使用該擴展,遵循如下四步:

  1. 安裝 django-celery 庫

    <pre class=”brush: bash; gutter: false;”>
    $ pip install django-celery
    </pre>

  2. 把 djcelery 加到 INSTALLED_APPS 中

  3. 創建 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>

  4. 配置 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

接下來怎么辦

如果你想學習更多東西,請參考Celery 進階教程,然后你可以學習用戶指南

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,501評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,673評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,610評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,939評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,668評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,004評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,001評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,173評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,705評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,426評論 3 359
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,656評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,139評論 5 364
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,833評論 3 350
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,247評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,580評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,371評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,621評論 2 380

推薦閱讀更多精彩內容