在 Django 項(xiàng)目中使用 Celery

Celery 先前的版本需要額外安裝一個(gè)庫(kù)才能與 Django 集成,但是自3.1版本開(kāi)始,再也不需要了?,F(xiàn)在 Celery 直接支持 Django 了,本文提供一個(gè)比較基本的方法將 Celery 集成到 Django 項(xiàng)目中。你將使用與非 Django 用戶同樣的API,所以在閱讀本文之前最好看一下Celery 初步。當(dāng)你完成一個(gè)可以正常運(yùn)行的例子后,再看看Celery 進(jìn)階

為了在 Django 項(xiàng)目中使用 Celery,必須先定義一個(gè) Celery 實(shí)例(也叫做 app)。

假如 Django 項(xiàng)目布局是這樣的:

- proj/
  - proj/__init__.py
  - proj/settings.py
  - proj/urls.py
- manage.py

那么,推薦的做法是創(chuàng)建一個(gè)新的 proj/proj/celery.py 模塊,然后在這個(gè)模塊中定義 Celery 實(shí)例。

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 模塊中導(dǎo)入這個(gè) Celery 實(shí)例(也就是 app)。這樣可以確保當(dāng) Django 啟動(dòng)時(shí)可以加載這個(gè) app,并且 @shared_task 裝飾器(后面會(huì)提到)也能使用這個(gè) 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

需要注意的是,上述項(xiàng)目布局示例適合大型項(xiàng)目。對(duì)于簡(jiǎn)單的項(xiàng)目,你可以在一個(gè)模塊中同時(shí)定義 Celery 實(shí)例和任務(wù),就像Celery 初步里面那樣。

我們看看在 proj/proj/celery.py 模塊中到底做了什么事。首先,從 future 模塊導(dǎo)入 absolute_import,這樣,celery.py 模塊就不會(huì)與 Celery 庫(kù)相沖突:

from __future__ import absolute_import

然后,為 celery 命令行程序設(shè)置環(huán)境變量 DJANGO_SETTINGS_MODULE 的默認(rèn)值:

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'proj.settings')

設(shè)置這個(gè)環(huán)境變量是為了讓 celery 命令能找到 Django 項(xiàng)目。這條語(yǔ)句必須出現(xiàn)在 Celery 實(shí)例創(chuàng)建之前,也就是接下來(lái)要做的:

app = Celery('proj')

這個(gè) app 就是 Celery 實(shí)例??梢杂泻芏?Celery 實(shí)例,但是當(dāng)使用 Django 時(shí),似乎沒(méi)有必要。

我們也將 Django settings 模塊作為 Celery 的配置來(lái)源。也就是說(shuō),不需要使用多個(gè)配置文件,直接在 Django settings 里面配置 Celery.

可以將 settings 對(duì)象作為參數(shù)傳入,但是更好的方式是使用字符串,因?yàn)楫?dāng)使用 Windows 系統(tǒng)或者 execv 時(shí) celery worker 不需要序列化 settings 對(duì)象:

app.config_from_object('django.conf:settings')

為了重用 Django APP,通常是在單獨(dú)的 tasks.py 模塊中定義所有任務(wù)。Celery 會(huì)自動(dòng)發(fā)現(xiàn)這些模塊:

app.autodiscover_tasks(lambda: settings.INSTALLED_APPS)

加上上一句后,Celery 會(huì)自動(dòng)發(fā)現(xiàn) Django APP 中定義的任務(wù),前提是遵循如下 tasks.py 約定:

- app1/
    - tasks.py
    - models.py
- app2/
    - tasks.py
    - models.py

這樣就不需要手動(dòng)把一個(gè)個(gè)模塊加到 CELERY_IMPORTS 配置中。傳入的 lambda 函數(shù)有如下好處:只在需要的時(shí)候才自動(dòng)發(fā)現(xiàn)任務(wù),以及當(dāng)導(dǎo)入模塊時(shí)不需要立即對(duì) settings 對(duì)象求值。

最后,debug_task 是一個(gè)打印本身 request 信息的任務(wù)。它使用了在 Celery 3.1引入的任務(wù)選項(xiàng) bind=True,使得引用當(dāng)前任務(wù)實(shí)例變得很容易。

使用 @shared_task 裝飾器

你很可能在可重用的 Django APP 中編寫(xiě)了一些任務(wù),但是 Django APP 不能依賴于具體的 Django 項(xiàng)目,所以你無(wú)法直接導(dǎo)入 Celery 實(shí)例。

@shared_task 裝飾器能讓你在沒(méi)有具體的 Celery 實(shí)例時(shí)創(chuàng)建任務(wù):

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)

另請(qǐng)參閱

你可以在這里找到這個(gè) Django 示例項(xiàng)目的完整源碼。

使用 Django ORM/Cache 作為結(jié)果存儲(chǔ)后端(result backend)

如果想在 Django 數(shù)據(jù)庫(kù)中保存任務(wù)執(zhí)行結(jié)果,還需要安裝 django-celery 庫(kù)(或者使用 SQLAlchemy 結(jié)果存儲(chǔ)后端)。

django-celery 庫(kù)基于 Django ORM和緩存框架實(shí)現(xiàn)了結(jié)果存儲(chǔ)后端.

為了在項(xiàng)目中使用該擴(kuò)展,遵循如下四步:

  1. 安裝 django-celery 庫(kù)

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

  2. 把 djcelery 加到 INSTALLED_APPS 中

  3. 創(chuàng)建 celery 用到的數(shù)據(jù)庫(kù)表

    當(dāng)使用數(shù)據(jù)庫(kù)作為結(jié)果存儲(chǔ)后端時(shí),這一步會(huì)創(chuàng)建用來(lái)保存任務(wù)結(jié)果的相關(guān)數(shù)據(jù)庫(kù)表,以及周期任務(wù)調(diào)度器需要使用的數(shù)據(jù)庫(kù)表。如果不使用周期任務(wù)和任務(wù)結(jié)果,可以跳過(guò)這一步。

    如果使用 south 來(lái)做模式遷移,執(zhí)行:

    <pre class=”brush: bash; gutter: false;”>
    $ python manage.py migrate djcelery
    </pre>

    如果不使用 south,執(zhí)行:

    <pre class=”brush: bash; gutter: false;”>
    $ python manage.py syncdb
    </pre>

  4. 配置 celery 使用 django-celery 結(jié)果存儲(chǔ)后端

    對(duì)于數(shù)據(jù)庫(kù)后端,使用:

    <pre class=”brush: python; gutter: false;”>
    app.conf.update(
    CELERY_RESULT_BACKEND='djcelery.backends.database:DatabaseBackend',
    )
    </pre>

    對(duì)于緩存后端,使用:

    <pre class=”brush: python; gutter: false;”>
    app.conf.update(
    CELERY_RESULT_BACKEND='djcelery.backends.cache:CacheBackend',
    )
    </pre>

    如果你將 Django settings 作為 Celery 的配置來(lái)源,可以直接在 settings 模塊中加上 CELERY_RESULT_BACKEND 配置項(xiàng),不需要 app.conf.update

相對(duì)導(dǎo)入

在導(dǎo)入任務(wù)模塊時(shí),必須保持一致性。也就是說(shuō),如果在 INSTALLED_APPS 中添加的是 project.app,那么需要以 from project.app 的方式導(dǎo)入任務(wù),否則任務(wù)的名稱將會(huì)不一樣。
參見(jiàn)自動(dòng)命名與相對(duì)導(dǎo)入

啟動(dòng) worker 進(jìn)程

在生產(chǎn)環(huán)境中,你希望在后臺(tái)以守護(hù)進(jìn)程的方式運(yùn)行 worker(參見(jiàn)以守護(hù)進(jìn)程運(yùn)行 worker),但是在測(cè)試開(kāi)發(fā)環(huán)境中,像 Django 的 runserver 那樣使用 celery worker 管理命令來(lái)啟動(dòng)一個(gè) worker 實(shí)例,就有用多了:

$ celery worker -A proj -l info

要查看 celery 的完整命令行選項(xiàng),使用 help 命令:

$ celery help

接下來(lái)怎么辦

如果你想學(xué)習(xí)更多東西,請(qǐng)參考Celery 進(jìn)階教程,然后你可以學(xué)習(xí)用戶指南。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容