Django+Celery+xadmin實(shí)現(xiàn)異步任務(wù)和定時任務(wù)

Django+Celery+xadmin實(shí)現(xiàn)異步任務(wù)和定時任務(wù)

關(guān)注公眾號“輕松學(xué)編程”了解更多。

一、celery介紹

1、簡介

【官網(wǎng)】http://www.celeryproject.org/

Celery 是一個強(qiáng)大的分布式任務(wù)隊列,它可以讓任務(wù)的執(zhí)行完全脫離主程序,甚至可以被分配到其他主機(jī)上運(yùn)行。我們通常使用它來實(shí)現(xiàn)異步任務(wù)( async task )和定時任務(wù)( crontab )。

  • 異步任務(wù):比如發(fā)送郵件、短信,或者文件上傳, 圖像處理等等一些比較耗時的操作 ;

  • 定時任務(wù):需要在特定時間執(zhí)行的任務(wù)。

架構(gòu)組成如圖:

image

2、Celery 主要包含以下幾個模塊

2.1 任務(wù)模塊 Task

異步任務(wù)通常在業(yè)務(wù)邏輯中被觸發(fā)并發(fā)往任務(wù)隊列;

定時任務(wù)由 Celery Beat 進(jìn)程周期性地將任務(wù)發(fā)往任務(wù)隊列。

2.2 消息中間件 Broker

Broker,即為任務(wù)調(diào)度隊列,接收任務(wù)生產(chǎn)者發(fā)來的消息(即任務(wù)),將任務(wù)存入隊列。 Celery 本身不提供隊列服務(wù),官方推薦使用 RabbitMQ 和 Redis 等。

2.3 任務(wù)執(zhí)行單元 Worker

Worker 是執(zhí)行任務(wù)的處理單元,它實(shí)時監(jiān)控消息隊列,獲取隊列中調(diào)度的任務(wù),并執(zhí)行它。

2.4 任務(wù)結(jié)果存儲 Backend

Backend 用于存儲任務(wù)的執(zhí)行結(jié)果,以供查詢。同消息中間件一樣,存儲也可使用RabbitMQ, Redis 和 MongoDB 等。 MQ全稱為Message Queue。

消息隊列(MQ)是不同的應(yīng)用程序相互通信的一種方法。

MQ是消費(fèi)者-生產(chǎn)者模型的一個典型的代表,一端往消息隊列中不斷寫入消息,而另一端則可以讀取隊列中的消息。

二、異步任務(wù)

假設(shè)已經(jīng)有了一個Django項(xiàng)目(我的項(xiàng)目名是MySites),下面演示如何使用Celery實(shí)現(xiàn)異步任務(wù)。

1、安裝celery

pip install celery
pip install django-celery
pip install redis==2.10.6
pip install django_celery_beat

注意:如果出現(xiàn)以下錯誤,一般是celery版本不對,重新安裝較高版本即可。

Running django in virtualenv - ImportError: No module name django.core.management

2、配置settings.py

我使用Redis作為消息隊列。

在settings.py中增加:

#django-celery
import djcelery
?
djcelery.setup_loader()
#使用本地redis服務(wù)器中的0號數(shù)據(jù)庫,redis密碼為123456
BROKER_URL = 'redis://:123456@127.0.0.1:6379/0'
CELERYBEAT_SCHEDULER = 'djcelery.schedulers.DatabaseScheduler'
CELERY_RESULT_BACKEND = 'redis://:123456@127.0.0.1:6379/1'
CELERY_ENABLE_UTC = False
CELERY_TIMEZONE = 'Asia/Shanghai'
CELERY_TASK_RESULT_EXPIRES = 10
CELERYD_LOG_FILE = BASE_DIR + "/logs/celery/celery.log"
CELERYBEAT_LOG_FILE = BASE_DIR + "/logs/celery/beat.log"
CELERY_ACCEPT_CONTENT = ['pickle', 'json', 'msgpack', 'yaml']
?```

其中,當(dāng)djcelery.setup_loader()運(yùn)行時,Celery便會去查看INSTALLD_APPS下包含的所有app目錄中的tasks.py文件,找到標(biāo)記為task的方法,將它們注冊為celery_task。

BROKER_URL和CELERY_RESULT_BACKEND分別指代你的Broker的代理地址以及Backend(result store)數(shù)據(jù)存儲地址。

在Django中如果沒有設(shè)置backend,會使用其默認(rèn)的后臺數(shù)據(jù)庫用來存儲數(shù)據(jù)。

注冊celery應(yīng)用:

```python
INSTALLED_APPS = [
 #其它應(yīng)用
 ...
 #celery應(yīng)用
 'djcelery',
]

3、創(chuàng)建celery.py文件

在項(xiàng)目中Mysites下創(chuàng)建celery.py文件(與settings.py同級)

image

內(nèi)容為:

from celery import Celery
from django.conf import settings
import os
?
# 為celery設(shè)置環(huán)境變量, 改為你項(xiàng)目的settings
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'MySites.settings')
?
# 創(chuàng)建應(yīng)用
app = Celery('mysites')
?
# 配置應(yīng)用
app.conf.update(
 # 本地Redis服務(wù)器
 BROKER_URL=settings.BROKER_URL,
)
?
app.autodiscover_tasks(settings.INSTALLED_APPS)

4、創(chuàng)建tasks.py文件

在子應(yīng)用app下創(chuàng)建tasks.py:

image

內(nèi)容為:

from MySites.celery import app
?
@app.task
def start_running(info):
 print(info)
 print('--->>開始執(zhí)行任務(wù)<<---')
 print('比如發(fā)送短信或郵件')
 print('>---任務(wù)結(jié)束---<')

5、修改views.py

在views.py中增加需要執(zhí)行的異步任務(wù),比如:

from SitesApp.tasks import start_running
?
#celery測試
class CeleryTask(View):
 def get(self, request):
 print('>=====開始發(fā)送請求=====<')
 start_running.delay('發(fā)送短信')
 # start_running.apply_async(('發(fā)送短信',), countdown=10)  # 10秒后再執(zhí)行異步任務(wù)
 return HttpResponse('<h2> 請求已發(fā)送 </h2>')

其實(shí)關(guān)鍵代碼就一條start_running.delay(參數(shù)),當(dāng)執(zhí)行這條代碼時,系統(tǒng)會把tasks.py中的start_running函數(shù)推遲執(zhí)行,即放入消息隊列中。

系統(tǒng)相當(dāng)于跳過start_running.delay('發(fā)送短信')執(zhí)行后面的語句,這就是異步任務(wù)。

6、修改項(xiàng)目下(不是子應(yīng)用下)的urls.py

from SitesApp import views
?
urlpatterns = [
 #其它url
 ...
 #celery測試url
 url('^celery/',views.CeleryTask.as_view()),
]

7、啟動服務(wù)

在Terminal中輸入:

python manage.py runserver

在另一個Terminal中:

celery -A MySites worker --loglevel=DEBUG
image
image

8、查看異步任務(wù)情況

Celery提供了一個工具flower,將各個任務(wù)的執(zhí)行情況、各個worker的健康狀態(tài)進(jìn)行監(jiān)控并以可視化的方式展現(xiàn),如下圖所示:

image

下實(shí)現(xiàn)的方式如下:

  1. 安裝flower:

pip install flower


2.  啟動flower(默認(rèn)會啟動一個webserver,端口為5555):

    在另一個Terminal中:

    ```python
python manage.py celery flower

3.進(jìn)入http://localhost:5555即可查看。

9、一些錯誤解決方法

錯誤1:

Celery ValueError: not enough values to unpack (expected 3, got 0)

看別人描述大概就是說win10上運(yùn)行celery4.x就會出現(xiàn)這個問題,解決辦法如下,原理未知:

先安裝一個``eventlet`

pip install eventlet

啟動worker時加上參數(shù)-P eventlet

celery -A MySites worker --loglevel=DEBUG -P eventlet

三、定時任務(wù)

1、配置settings.py

注冊django_celery_beat應(yīng)用:

INSTALLED_APPS = [
 #其它應(yīng)用
 ...
 #django_celery_beat應(yīng)用
 'django_celery_beat',
]

2、配置項(xiàng)目目錄下的__init__()

from __future__ import absolute_import
from MySites.celery import app as celery_app

import pymysql
pymysql.install_as_MySQLdb()

image

3、修改celery.py文件

修改項(xiàng)目目錄(和settings.py)同級的celery.py:

from __future__ import absolute_import

import os
from celery import Celery, platforms
from django.conf import settings

# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'MySites.settings')

# MySites主應(yīng)用名
app = Celery('mysites')
platforms.C_FORCE_ROOT = True

# 配置應(yīng)用
app.conf.update(
    # 本地Redis服務(wù)器
    BROKER_URL=settings.BROKER_URL,

)

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

@app.task(bind=True)
def debug_task(self):
    print('Request: {0!r}'.format(self.request))

4、修改adminx.py文件

我使用xadmin作為后臺管理。增加以下代碼:

#adminx.py
from __future__ import absolute_import, unicode_literals
from djcelery.models import (
  TaskState, WorkerState,
  PeriodicTask, IntervalSchedule, CrontabSchedule,
)

#celery

xadmin.site.register(IntervalSchedule) # 存儲循環(huán)任務(wù)設(shè)置的時間
xadmin.site.register(CrontabSchedule) # 存儲定時任務(wù)設(shè)置的時間
xadmin.site.register(PeriodicTask) # 存儲任務(wù)
xadmin.site.register(TaskState) # 存儲任務(wù)執(zhí)行狀態(tài)
xadmin.site.register(WorkerState) # 存儲執(zhí)行任務(wù)的worker

5、修改tasks.py文件

from __future__ import absolute_import
from MySites.celery import app
from celery import task, shared_task

@app.task
def start_running(info):
    print(info)
    print('--->>開始執(zhí)行任務(wù)<<---')
    print('比如發(fā)送短信或郵件')
    print('>---任務(wù)結(jié)束---<')

@task
def pushMsg(uid,msg):
    print('推送消息',uid,msg)
    return True

@shared_task
def add(x,y):
    print('加法:',x + y)
    return x + y

@shared_task
def mul(x, y):
    print('乘法',x*y)
    return x * y

6、數(shù)據(jù)庫遷移和創(chuàng)建管理員

python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser

8、啟動服務(wù)器

python manage.py runserver

在瀏覽器打開http://127.0.0.1:10501/xadmin/

Crontabs:定時任務(wù)執(zhí)行時間;

Intervals:簡單的間隔執(zhí)行時間,比如每10秒執(zhí)行一次;

Periodic tasks:配置定時任務(wù);

Tasks:任務(wù)監(jiān)控;

Workers:運(yùn)行的worker。

image

配置執(zhí)行時間:

image

添加定時任務(wù):

image

9、終端啟動celery命令

# 啟動
#linux下
celery -A MySites worker -B  # MySites為celery和setting所在文件夾名
#Windows下先啟動celery-beat
celery -A MySites beat -l debug --max-interval=10
#然后再啟動worker
celery -A MySites worker -l debug -P eventlet
#注意:在正式環(huán)境下把debug改為info

# 查看注冊的task
celery -A MySites inspect registered

# flower監(jiān)控celery
celery flower
ip:5555

注意:出現(xiàn)以下錯誤是windows不支持celery4.0以上版本,降低為3.1版本即可

SystemError: <class 'OSError'> returned a result with an error set 
pip uninstall celery
pip install celery==3.1.22

補(bǔ)充:celery4.0以上版本不再支持 Microsoft Windows ,不再支持使用Django ORM作為代理 。

10、服務(wù)器使用Supervisor后臺運(yùn)行Celery

pip install supervisor

我們可以使用echo_supervisord_conf命令得到supervisor配置模板,打開終端執(zhí)行如下Linux shell命令:

echo_supervisord_conf > supervisord.conf

該命令輸出文件到當(dāng)前目錄下(當(dāng)然,你也可以指定絕對路徑到具體位置),文件名為supervisord.conf 修改supervisord.conf文件,在文件最后加入:

[program:celery.worker] 
;指定運(yùn)行目錄 
directory=/home/你的項(xiàng)目名稱
;運(yùn)行目錄下執(zhí)行命令
command=celery -A 你的項(xiàng)目名稱worker --loglevel info --logfile celery_worker.log

;啟動設(shè)置 
numprocs=1          ;進(jìn)程數(shù)
autostart=true      ;當(dāng)supervisor啟動時,程序?qū)詣訂?
autorestart=true    ;自動重啟

;停止信號,默認(rèn)TERM 
;中斷:INT (類似于Ctrl+C)(kill -INT pid),退出后會將寫文件或日志(推薦) 
;終止:TERM (kill -TERM pid) 
;掛起:HUP (kill -HUP pid),注意與Ctrl+Z/kill -stop pid不同 
;從容停止:QUIT (kill -QUIT pid) 
stopsignal=INT
;輸出日志 
stdout_logfile=celery_worker.log 
stdout_logfile_maxbytes=10MB  ;默認(rèn)最大50M 
stdout_logfile_backups=10     ;日志文件備份數(shù),默認(rèn)為10 

;錯誤日志 
redirect_stderr=false         ;為true表示禁止監(jiān)聽錯誤 
stderr_logfile=celery_worker_err.log 
stderr_logfile_maxbytes=10MB 
stderr_logfile_backups=10

啟動supervisor輸入如下命令,使用具體的配置文件執(zhí)行: 先運(yùn)行虛擬環(huán)境

supervisord -c supervisord.conf

關(guān)閉supervisor輸入如下命令:

supervisorctl -c supervisord.conf shutdown

重啟supervisor輸入如下命令:

supervisorctl -c supervisord.conf reload

后記

【后記】為了讓大家能夠輕松學(xué)編程,我創(chuàng)建了一個公眾號【輕松學(xué)編程】,里面有讓你快速學(xué)會編程的文章,當(dāng)然也有一些干貨提高你的編程水平,也有一些編程項(xiàng)目適合做一些課程設(shè)計等課題。

也可加我微信【1257309054】,拉你進(jìn)群,大家一起交流學(xué)習(xí)。 如果文章對您有幫助,請我喝杯咖啡吧!

公眾號

image
image

關(guān)注我,我們一起成長~~

【參考文章】: http://yshblog.com/blog/165 https://www.jb51.net/article/133507.htm

https://blog.csdn.net/Shyllin/article/details/80940643

https://www.cnblogs.com/znicy/p/5626040.html

https://blog.csdn.net/qq_30242609/article/details/79047660

https://www.jb51.net/article/145573.htm

https://www.cnblogs.com/dengshihuang/p/8258621.html

https://blog.csdn.net/yeyingcai/article/details/78647553

http://www.manongjc.com/article/5685.htmlhttps://www.cnblogs.com/huangxiaoxue/p/7266253.html

https://blog.csdn.net/xiemanr/article/details/70331120

http://www.linuxdiyf.com/viewarticle.php?id=562707

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

推薦閱讀更多精彩內(nèi)容