天天看點

Django中使用Celery實作定時任務(用djcelery)

一.引言

Django是python語言下的一個比較熱門的Web架構,越來越多的企業和開發者使用Django實作自己的Web伺服器。在Web伺服器開發過程中,有時候我們不僅僅是要實作Web伺服器端和使用者端的簡單邏輯互動,還要實作一些定時任務。舉出以下的例子:  

  1. 定期删除或緩存Redis資料庫的記錄 

    為了追求更高的資料庫通路性能,我把Redis作為MySql資料庫的緩存。把常通路的資料放在Redis中,然後定時存儲到Mysql中。并且把過期的Redis資料删掉.那麼這個時候,就需要定時去完成這個任務。

  2. 生成報表    

    打個比方,你有一個Web電商伺服器,每天使用者都在會在上面購物。為了很友善的統計出每個使用者每個月的消費金額,你在資料庫中設計了一張月統計報表。然後使用定時任務,在每個月的1号進行統計,檢索資料庫,計算出每個使用者上個月的的消費金額,逐個存儲到月統計報表中。那麼這個生成報表的任務就是定時完成的,也就是前面提到的每個月的1号。

  3. 定時發送消息 

    再如:當你的網站上使用者生日來臨,你希望在他生日那天,給使用者的郵箱發送生日快樂的祝福。那麼這也是定時任務實作的。

上面這些的例子,都是需要定時任務。在Python中,我們使用的Celery子產品完成這項任務。網絡上關于Celery的博文很多,大多博文的邏輯比較混亂,是以就有了這篇博文。希望讀者有個清晰的認識,并且很好的實戰出來。

此篇博文沒有介紹Celery的工作原理,諸如Broker,Worker等等。在實戰之前,這些概念必須要了解清楚。由于網上已經有很多這樣的内容,我在文章結尾處貼出了一些參考文檔,友善讀者學習。

二.Celery,Django和Djcelery

始終明确的是: 

Celery是Python的第三方庫,它可以用于是任何的Python的項目中,因為我們始終可以把Celery看成一個獨立的子產品去操縱其它的子產品。是以,我們也可以在Django項目中使用的Celery,但值得注意的是,在Django中使用Celery的方式有兩種:

  1. 僅使用Celery。
  2. 同時使用Celery + djcelery .

方法1: 相當于中Django中加入了一個Celery的任務腳本,為了操縱Django,是以需要額外在Celery中配置Django環境,才能操作Django的資料庫。

方法2: 由于使用了djcelery,可以在任務中友善的直接操作Django資料庫,而且最終的任務可以在Django的背景中檢視和修改相關的任務。

兩種方法的選擇: 

從上面的描述看,方法1比方法2少引入一個djcelery子產品,缺點是需要自己配置與Django結合的環境。而方法2,比較友善省心,還能在Django背景管理自己的任務。是以如果你在Django中使用Celery,我強烈推薦方法2。

這兩種方法我都寫了相應的博文。此篇博文講述了使用djcelery的方法2,至于不用的djcelery僅僅使用Celery子產品的方法1,請參考我的另一篇博文:   

Django中使用Celery實作定時任務(不使用djcelery)

但它們本質上是一樣的。

三. Django目錄結構

下面展示了一個Django項目的目錄結構示例: 

- app 

  - admin.py 

  - views.py 

  - urls.py 

  - models.py 

  - tasks.py 

- pro 

  - settings.py 

  - urls.py 

  - urls.py 

  - models.py 

- manage.py

注意,上述目錄中的

tasks.py

檔案是我建立的,放在app的目錄下,整個Celery任務,我隻建立了這一個檔案。

四. 配置setting.py

為了設定Celery,我們需要對setting.py檔案進行配置,過程如下:

1.加入djcelery

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'djcelery', #此處是新加入的djcelery
    'app',
)           

上述 

INSTALLED_APPS

中我省略了無關的子產品,注意加入

djcelery

即可。   

 

2. 設定celery參數

我在setting.py的檔案結尾處,加入了如下的celery參數配置,先貼代碼,再解釋。

import djcelery
djcelery.setup_loader()
BROKER_URL = 'redis://127.0.0.1:6379/6'
CELERY_IMPORTS = ('app.tasks', )
CELERY_TIMEZONE = TIME_ZONE
CELERYBEAT_SCHEDULER = 'djcelery.schedulers.DatabaseScheduler'

# 下面是定時任務的設定,我一共配置了三個定時任務.
from celery.schedules import crontab
CELERYBEAT_SCHEDULE = {
    #定時任務一: 每24小時周期執行任務(del_redis_data)
    u'删除過期的redis資料': {
        "task": "app.tasks.del_redis_data",
        "schedule": crontab(hour='*/24'),
        "args": (),
    },
    #定時任務二: 每天的淩晨12:30分,執行任務(back_up1)
    u'生成日報表': {
        'task': 'app.tasks.back_up1',
        'schedule': crontab(minute=30, hour=0),
        "args": ()
    },
    #定時任務三:每個月的1号的6:00啟動,執行任務(back_up2)
    u'生成統計報表': {
            'task': 'app.tasks.back_up2',
            'schedule': crontab(hour=6, minute=0,   day_of_month='1'),
            "args": ()
    },
}           

上述代碼釋義:

當djcelery.setup_loader()運作時,Celery便會去檢視INSTALLD_APPS下包含的所有app目錄中的tasks.py檔案,找到标記為task的方法,将它們注冊為celery task。

1.

BROKER_URL = 'redis://127.0.0.1:6379/6'           

broker是代理人,它負責分發任務給worker去執行。我使用的是Redis作為broker,當然你也可以用其它的broker,比如官方就比較推薦使用RabbitMQ.

有的部落格中提到要配置關鍵字:

CELERY_RESULT_BACKEND

,例如:

CELERY_RESULT_BACKEND = 'amqp://guest@localhost//' #可以不用寫           

我沒有配置這個關鍵字。因為如果沒有配置,此時Django會使用預設的資料庫(也是你指定的orm資料庫),作為它的結果作為它的backend。是以你也可以不用寫,使用Django預設設定的資料庫就很好。 

2.

CELERY_IMPORTS = ('app.tasks', )
CELERY_TIMEZONE = TIME_ZONE
CELERYBEAT_SCHEDULER = 'djcelery.schedulers.DatabaseScheduler'           

上面第一句是導入目标任務檔案,第二句是設定時區,第三句表示使用了django-celery預設的資料庫排程模型,任務執行周期都被存在預設指定的orm資料庫中.

更深入的Celery配置:(http://www.cnblogs.com/ajianbeyourself/p/4950758.html) 

3.

from celery.schedules import crontab
CELERYBEAT_SCHEDULE = {
    #定時任務一: 每24小時周期執行任務(del_redis_data)
    u'删除過期的redis資料': {
        "task": "app.tasks.del_redis_data",
        "schedule": crontab(hour='*/24'),
        "args": (),
    },           

上面是設定定時的時間配置,關于

crontab

的用法,官方的文檔講解的十分詳盡(文檔末尾的表格):

http://docs.celeryproject.org/en/latest/userguide/periodic-tasks.html

5.Tasks任務

每個任務本質上就是一個函數,在tasks.py中,寫入你想要執行的函數即可。我的tasks.py如下:我寫的每個任務又臭又長,是以具體的細節就省略了。

# coding=utf-8
from celery import task

@task()
def del_redis_data():
    # 此處是一個删除redis資料的操作。具體略過

@task()
def back_up1():
    # 此處是一個備份到日報表的操作。具體略過

@task()
def back_up2():
    # 此處是一個生成統計報表的操作。具體略過           

如果讀者需要自己實作一個定時任務,那麼上述的task函數必然要自己去定義,我隻提供了參考。我上面的三個任務,分别對應了

setting.py

檔案的

CELERYBEAT_SCHEDULE

的三個定時配置。

要記住的是,任務隻是一個函數,這個函數什麼時候調用,取決你在

setting.py

中的配置。

6.啟動定時任務

待續: 

登入到Django背景,可以看到

7.推薦文章

1.更深入的Celery配置:(http://www.cnblogs.com/ajianbeyourself/p/4950758.html)