Django項(xiàng)目中使用celery做異步任務(wù)

異步任務(wù)介紹

在寫項(xiàng)目過(guò)程中經(jīng)常會(huì)遇到一些耗時(shí)的任務(wù), 比如:發(fā)送郵件席楚、發(fā)送短信等等~城菊。這些操作如果都同步執(zhí)行耗時(shí)長(zhǎng)對(duì)用戶體驗(yàn)不友好,在這種情況下就可以把任務(wù)放在后臺(tái)異步執(zhí)行
celery就是用于處理異步任務(wù)的框架,celery能完成的功能遠(yuǎn)不止異步任務(wù),還有一個(gè)很常用的功能定時(shí)任務(wù)

架構(gòu)圖

架構(gòu).png

Celery包含如下組件:

  • Celery Beat:任務(wù)調(diào)度器撕彤,Beat進(jìn)程會(huì)讀取配置文件的內(nèi)容,周期性地將配置中到期需要執(zhí)行的任務(wù)發(fā)送給任務(wù)隊(duì)列场仲。

  • Celery Worker:執(zhí)行任務(wù)的消費(fèi)者法竞,通常會(huì)在多臺(tái)服務(wù)器運(yùn)行多個(gè)消費(fèi)者來(lái)提高執(zhí)行效率。

  • Broker:消息代理鹉动,或者叫作消息中間件轧坎,接受任務(wù)生產(chǎn)者發(fā)送過(guò)來(lái)的任務(wù)消息,存進(jìn)隊(duì)列再按序分發(fā)給任務(wù)消費(fèi)方(通常是消息隊(duì)列或者數(shù)據(jù)庫(kù))泽示。

  • Producer:調(diào)用了Celery提供的API缸血、函數(shù)或者裝飾器而產(chǎn)生任務(wù)并交給任務(wù)隊(duì)列處理的都是任務(wù)生產(chǎn)者。

  • Result Backend:任務(wù)處理完后保存狀態(tài)信息和結(jié)果械筛,以供查詢捎泻。Celery默認(rèn)已支持Redis、RabbitMQ埋哟、MongoDB笆豁、Django ORM、SQLAlchemy等方式赤赊。

Celery 安裝

pip install django-celery celery-with-redis

項(xiàng)目結(jié)構(gòu)

[vagrant@reboot test_drf]$ tree opsweb/
opsweb/
├── apps
│   ├── account
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── __init__.py
│   │   ├── migrations
│   │   ├── models.py
│   │   ├── __pycache__
│   │   ├── tasks.py
│   │   ├── tests.py
│   │   └── views.py
├── celerybeat.pid
├── logs
│   ├── celery
│   │   ├── beat.log
│   │   └── celery.log
├── manage.py
├── opsweb
│   ├── celery.py
│   ├── __init__.py
│   ├── __pycache__
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py

加載celery app(settings文件中)

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'corsheaders',
    'rest_framework',
    'rest_framework_swagger',
    'account',
    'djcelery' # celery app 很強(qiáng)大
]

添加Celery全局配置(settings文件中)

# Celery
import djcelery
djcelery.setup_loader()  # 加載djcelery

CELERY_TIMEZONE = TIME_ZONE
CELERY_ENABLE_UTC = True

# 允許的格式
CELERY_ACCEPT_CONTENT = ['pickle', 'json', 'yaml']

BROKER_URL = 'redis://127.0.0.1:6379/0'     # redis作為中間件
BROKER_TRANSPORT = 'redis'
CELERYBEAT_SCHEDULER = 'djcelery.schedulers.DatabaseScheduler'     # Backend數(shù)據(jù)庫(kù)

# CELERYD_LOG_FILE = BASE_DIR + "/logs/celery/celery.log"         # log路徑
# CELERYBEAT_LOG_FILE = BASE_DIR + "/logs/celery/beat.log"     # beat log路徑

同步Celery表到數(shù)據(jù)庫(kù)

python manage.py migrate

創(chuàng)建celery.py文件(與settings同級(jí))

import os
import django
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', 'opsweb.settings')
django.setup()
app = Celery('opsweb')
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))

創(chuàng)建任務(wù)文件

在需要使用異步任務(wù)的app中創(chuàng)建tasks.py,寫入對(duì)應(yīng)的任務(wù)函數(shù),博主喜歡把tasks放在對(duì)應(yīng)的app下,其實(shí)放在其他目錄下也可以的,看個(gè)人習(xí)慣

from opsweb.celery import app
from celery.schedules import crontab
import traceback
from django.contrib.auth.models import User
import os
@app.task(name="create_user")
def useradd(username):
   try:
        print(username)
   except:
        print('fail')
        traceback.print_exc()

觸發(fā)任務(wù)

在對(duì)應(yīng)的視圖中導(dǎo)入tasks中的任務(wù)函數(shù)調(diào)用即可

from account.tasks import useradd
# 調(diào)用異步任務(wù)函數(shù)
useradd.delay('username')

啟動(dòng)Celery

進(jìn)入opsweb工程下,啟動(dòng)Celery

[vagrant@reboot opsweb]$celery -A opsweb worker -B -l info
或:
[vagrant@reboot opsweb]$python manage.py celery worker -B -l info

備注:
本場(chǎng)景用戶訪問(wèn)觸發(fā)任務(wù)闯狱,流程如下:
用戶頁(yè)面上點(diǎn)擊事件->調(diào)用任務(wù)/定時(shí)計(jì)劃任務(wù)->任務(wù)進(jìn)入redis隊(duì)列
->如果celery啟動(dòng)則依次執(zhí)行任務(wù)->如果celery沒(méi)啟動(dòng),則會(huì)存到redis

隊(duì)列里抛计,一旦啟動(dòng)就依次執(zhí)行

啟動(dòng)Django

[vagrant@reboot opsweb]$python manage.py runserver 0:8000

測(cè)試

頁(yè)面上觸發(fā)了異步任務(wù)就會(huì)在celery日志里看到任務(wù)信息,我這里只是寫了簡(jiǎn)單的任務(wù)例子

[2018-09-01 23:56:59,704: WARNING/Worker-2] hello
[2018-09-01 23:56:59,707: INFO/MainProcess] Received task: create_user[c9724e23-b9ba-44fc-b195-6b1153d2c161]
[2018-09-01 23:56:59,708: INFO/MainProcess] Task create_user[f3b3e644-b8aa-4679-8a42-0efc2574abf6] succeeded in 0.0038937819999773637s: None

計(jì)劃任務(wù) - djcelery

djcelery app提供了定時(shí)任務(wù)的功能哄孤,注冊(cè)并同步到數(shù)據(jù)庫(kù)之后,會(huì)生產(chǎn)五個(gè)表吹截,結(jié)構(gòu)如下:

MariaDB [test002]> show tables
    -> ;
+---------------------------+
| Tables_in_test002         |
+---------------------------+
...
| djcelery_crontabschedule  |
| djcelery_intervalschedule |
| djcelery_periodictask     |
| djcelery_periodictasks    |
| djcelery_taskstate        |
| djcelery_workerstate      |
+---------------------------+

在django后臺(tái)可以看到注冊(cè)的表


定時(shí)任務(wù).png

每個(gè)任務(wù)可以接受參數(shù)

job.png

定時(shí)任務(wù)函數(shù)

from opsweb.celery import app
@app.task(name="create_user"  )
def create_user(*args,**kwargs): # 分別接收后臺(tái)傳入的列表和字典參數(shù)
    print (args,kwargs)

啟動(dòng)Celery beat

[vagrant@reboot opsweb]$ python manage.py celery beat # 啟動(dòng)定時(shí)任務(wù)

Celery會(huì)通過(guò)celery beat進(jìn)程來(lái)完成. Celerybeat會(huì)保持運(yùn)行, 一旦到了某一定期任務(wù)需要執(zhí)行時(shí), Celery beat便將其加入到queue中

supervisor管理Celery任務(wù)

配置如下

  • 主動(dòng)觸發(fā)任務(wù)
celery_worker.conf
[program:celery_worker]
# 進(jìn)入工作目錄
directory=/vagrant/test_drf/opsweb
# 執(zhí)行celery指令
command=python manage.py celery worker -B -l info
autorestart=true
loglevel=info
redirect_stderr=true
stdout_logfile=/var/log/supervisor/celery_worker.log
  • 定時(shí)任務(wù)觸發(fā)
celery_beat.conf 同上, 區(qū)別如下:
[program:celery_beat]
command=python manage.py celery beat
stdout_logfile=/var/log/supervisor/celery_beat.log

一些不錯(cuò)的文章
http://www.cnblogs.com/znicy/p/5626040.html Django中使用celery瘦陈,非常經(jīng)典
https://www.cnblogs.com/huangxiaoxue/p/7266253.html 基于celery開(kāi)發(fā)的平臺(tái),非常棒
http://python.jobbole.com/81953/ 劉天斯大神 經(jīng)典案例
http://www.imooc.com/article/16164 慕課網(wǎng)老師博客
http://blog.csdn.net/michael_lbs/article/details/74923367 python+django+djcelery
http://blog.csdn.net/lizhihua0925/article/details/53842110 model api

http://www.reibang.com/p/7085dcc70d0e 挺好
http://blog.csdn.net/crb912/article/details/78344659 很詳細(xì)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市波俄,隨后出現(xiàn)的幾起案子晨逝,更是在濱河造成了極大的恐慌,老刑警劉巖懦铺,帶你破解...
    沈念sama閱讀 221,576評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件捉貌,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)昏翰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門苍匆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人棚菊,你說(shuō)我怎么就攤上這事∈逯” “怎么了统求?”我有些...
    開(kāi)封第一講書人閱讀 168,017評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)据块。 經(jīng)常有香客問(wèn)我码邻,道長(zhǎng),這世上最難降的妖魔是什么另假? 我笑而不...
    開(kāi)封第一講書人閱讀 59,626評(píng)論 1 296
  • 正文 為了忘掉前任像屋,我火速辦了婚禮,結(jié)果婚禮上边篮,老公的妹妹穿的比我還像新娘己莺。我一直安慰自己,他們只是感情好戈轿,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布凌受。 她就那樣靜靜地躺著,像睡著了一般思杯。 火紅的嫁衣襯著肌膚如雪胜蛉。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 52,255評(píng)論 1 308
  • 那天色乾,我揣著相機(jī)與錄音誊册,去河邊找鬼。 笑死暖璧,一個(gè)胖子當(dāng)著我的面吹牛案怯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播漆撞,決...
    沈念sama閱讀 40,825評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼殴泰,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了浮驳?” 一聲冷哼從身側(cè)響起悍汛,我...
    開(kāi)封第一講書人閱讀 39,729評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎至会,沒(méi)想到半個(gè)月后离咐,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,271評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評(píng)論 3 340
  • 正文 我和宋清朗相戀三年宵蛀,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了昆著。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,498評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡术陶,死狀恐怖凑懂,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情梧宫,我是刑警寧澤接谨,帶...
    沈念sama閱讀 36,183評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站塘匣,受9級(jí)特大地震影響脓豪,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜忌卤,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評(píng)論 3 333
  • 文/蒙蒙 一扫夜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧驰徊,春花似錦笤闯、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,338評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至勋桶,卻和暖如春脱衙,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背例驹。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,458評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工捐韩, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人鹃锈。 一個(gè)月前我還...
    沈念sama閱讀 48,906評(píng)論 3 376
  • 正文 我出身青樓荤胁,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親屎债。 傳聞我的和親對(duì)象是個(gè)殘疾皇子仅政,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評(píng)論 2 359

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