Django 進階之 celery
Django 整合 Celery 到專案:本節將 celery 整合到 Django 專案中,實現非同步任務處理和定時任務處理。
Celery工作流程
Celery 的架構由三部分組成,訊息中介軟體(message broker),任務執行單元(worker)和任務執行結果儲存(task result store)組成。
訊息中介軟體
Celery 本身不提供訊息服務,但是可以方便的和第三方提供的訊息中介軟體整合。包括,RabbitMQ, Redis, MongoDB (experimental), Amazon SQS (experimental),CouchDB (experimental), SQLAlchemy (experimental),Django ORM (experimental), IronMQ。
任務執行單元
Worker 是 Celery 提供的任務執行的單元,worker 併發的執行在分散式的系統節點中。
任務結果儲存
Task result store 用來儲存 Worker 執行的任務的結果,Celery支援以不同方式儲存任務的結果,包括 AMQP, Redis,memcached, MongoDB,SQLAlchemy, Django ORM,Apache Cassandra, IronCache
1、Celery 安裝與配置
在虛擬環境中安裝:
pip install django-celery==3.2.2
pip install django-redis
pip install flower # celery 的 web 管理平臺(非同步任務視覺化)
檢視整合到 Django 中的 celery 版本, pip freeze
celery==3.1.26.post2 django-celery==3.2.2 flower==0.9.2
啟動 redis 服務, 埠假設為 6379
發現 pip 安裝比較慢的情況
pip install pillow -i https://pypi.doubanio.com/simple/
2、Django 中配置
(1)在主工程的配置檔案 settings.py 中應用登錄檔 INSTALLED_APPS 中加入 djcelery
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'art',
'xadmin',
'crispy_forms',
'DjangoUeditor',
'djcelery', #加入djcelery
]
(2)在 settings.py 中加入 celery 配置資訊
#############################
# celery 配置資訊 start
#############################
import djcelery
djcelery.setup_loader()
BROKER_URL = 'redis://127.0.0.1:6379/1'
CELERY_IMPORTS = ('art.tasks')
CELERY_TIMEZONE = 'Asia/Shanghai'
CELERYBEAT_SCHEDULER = 'djcelery.schedulers.DatabaseScheduler'
from celery.schedules import crontab
from celery.schedules import timedelta
CELERYBEAT_SCHEDULE = { #定時器策略
#定時任務一: 每隔30s執行一次
u'測試定時器1': {
"task": "art.tasks.tsend_email",
#"schedule": crontab(minute='*/2'), # or 'schedule': timedelta(seconds=3),
"schedule":timedelta(seconds=30),
"args": (),
},
}
#############################
# celery 配置資訊 end
#############################
當 djcelery.setup_loader() 執行時,Celery 便會去檢視 INSTALLD_APPS 下包含的所有 app 目錄中的 tasks.py 檔案,找到標記為task 的方法,將它們註冊為 celery task.
BROKER_URL:broker 是代理人,它負責分發任務給 worker 去執行。我使用的是 Redis 作為 broker。沒有設定 CELERY_RESULT_BACKEND,預設沒有配置,此時 Django 會使用預設的資料庫(也是你指定的 orm 資料庫)。
CELERY_IMPORTS:是匯入目標任務檔案。
CELERYBEAT_SCHEDULER:使用了 django-celery 預設的資料庫排程模型,任務執行週期都被存在預設指定的 orm 資料庫中。
CELERYBEAT_SCHEDULE:設定定時的時間配置, 可以精確到秒,分鐘,小時,天,周等。
(3)建立應用例項
在主工程目錄新增 celery.py, 新增自動檢索 django 工程 tasks 任務
vim artproject/celery.py
#!/usr/bin/env python
# encoding: utf-8
#目的是拒絕隱式引入,celery.py和celery衝突。
from __future__ import absolute_import,unicode_literals
import os
from celery import Celery
from django.conf import settings
# 設定環境變數
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "artproject.settings")
#建立celery應用
app = Celery('art_project')
app.config_from_object('django.conf:settings')
#如果在工程的應用中建立了tasks.py模組,那麼Celery應用就會自動去檢索建立的任務。比如你新增了一個任#務,在django中會實時地檢索出來。
app.autodiscover_tasks(lambda :settings.INSTALLED_APPS)
(4)建立任務 tasks
每個任務本質上就是一個函式,在 tasks.py 中,寫入你想要執行的函式即可。
在應用 art 中新增我們需要提供的非同步服務和定時服務。
vim art/tasks.py
#!/usr/bin/env python
# encoding: utf-8
from __future__ import absolute_import
import time
from django.core.mail import send_mail
from celery.utils.log import get_task_logger
from artproject.celery import app
from art.utils.send_mail import pack_html, send_email
@app.task
def tsend_email():
url = "http://1000phone.com"
receiver = 'diyuhuan@1000phone.com'
content = pack_html(receiver, url)
# content = 'this is email content.'
send_email(receiver, content)
print('send email ok!')
@app.task
def add(x, y):
return x+y
上述我們把非同步處理任務 add 和定時器任務 tsend_email 都放在了 tasks.py 中
(5)遷移生成 celery 需要的資料表
python manage.py migrate
此時資料庫表結構多出了幾個
celery_taskmeta |
| celery_tasksetmeta |
| djcelery_crontabschedule |
| djcelery_intervalschedule |
| djcelery_periodictask |
| djcelery_periodictasks |
| djcelery_taskstate |
| djcelery_workerstate
3、啟動服務,測試
我們可以採用 python manage.py help 發現多出了 celery 相關選項。
(1)啟動 django celery 服務
啟動服務:
python manage.py celery worker --loglevel=info
此時非同步處理和定時處理服務都已經啟動了
(2)web 端介面觸發非同步任務處理
我們在 web 端加入一個入口,觸發非同步任務處理 add 函式
在應用 art 的 urls.py 中加入如下對應關係
from art.views import add_handler
url(r'^add', add_handler),
art/views.py 中加入處理邏輯
def add_handler(request):
x = request.GET.get('x', '1')
y = request.GET.get('y', '1')
from .tasks import add
add.delay(int(x), int(y))
res = {'code':200, 'message':'ok', 'data':[{'x':x, 'y':y}]}
return HttpResponse(json.dumps(res))
啟動 web 服務,通過 url 傳入的引數,通過 handler 的 add.delay(x, y) 計算並存入 mysql
http://127.0.0.1:8000/art/add?x=188&y=22
(3)測試定時器,傳送郵件
在終端輸入 python manage.py celerybeat -l info
會自動觸發每隔 30s 執行一次 tsend_email 定時器函式,傳送郵件:
CELERYBEAT_SCHEDULE = { #定時器策略
#定時任務一: 每隔30s執行一次
u'測試定時器1': {
"task": "art.tasks.tsend_email",
#"schedule": crontab(minute='*/2'), # or 'schedule': timedelta(seconds=3),
"schedule":timedelta(seconds=30),
"args": (),
},
}
具體傳送郵件服務程式見下面的第 4 節
4、郵件傳送服務
專案中經常會有定時傳送郵件的情形,比如傳送資料包告,傳送異常服務報告等。
可以編輯檔案 art/utils/send_mail.py, 內容編輯如下:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
#written by diyuhuan
#傳送郵件(wd_email_check123賬號用於內部測試使用,不要用於其他用途)
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.image import MIMEImage
from email.header import Header
import time
sender = 'wd_email_check123@163.com'
subject = u'api開放平臺郵箱驗證'
smtpserver = 'smtp.163.com'
username = 'wd_email_check123'
password = 'wandacheck1234'
mail_postfix="163.com"
def send_email(receiver, content):
try:
me = username+"<"+username+"@"+mail_postfix+">"
msg = MIMEText(content, 'html', 'utf-8')
msg['Subject'] = subject
msg['From'] = sender
msg['To'] = receiver
smtp = smtplib.SMTP()
smtp.connect(smtpserver)
smtp.login(username, password)
smtp.sendmail(sender, receiver, msg.as_string())
smtp.quit()
return True
except Exception as e:
print('send_email has error with : ' + str(e))
return False
def pack_html(receiver, url):
html_content = u"<html><div>尊敬的使用者<font color='#0066FF'>%s</font> 您好!</div><br>" \
"<div>感謝您關注我們的平臺 ,我們將為您提供最貼心的服務,祝您購物愉快。</div><br>" \
"<div>點選以下連結,即可完成郵箱安全驗證:</div><br>" \
"<div><a href='%s'>%s</a></div><br>" \
"<div>為保障您的帳號安全,請在24小時內點選該連結; </div><br>" \
"<div>若您沒有申請過驗證郵箱 ,請您忽略此郵件,由此給您帶來的不便請諒解。</div>" \
"</html>" % (receiver, url, url)
html_content = html_content
return html_content
if __name__ == "__main__":
url = "http://1000phone.com"
receiver = 'diyuhuan@1000phone.com'
#content = pack_html(receiver, url)
content = 'this is email content. at %s.'%int(time.time())
send_email(receiver, content)
至此,在 celery ui 介面可以看到兩類,定時器處理和非同步處理。
5、啟動 flower 服務
python manager celery flower
案例
讀書網站實現搶讀功能
qd(request, id) :搶讀檢視函式
quereyQD(request,id) :查詢搶讀的檢視函式
settings.py
INSTALLED_APPS = [
'djcelery',
]
...
import djcelery
# 裝載djcelery物件
djcelery.setup_loader()
# 配置訊息中介軟體的位置
BROKER_URL = 'redis://127.0.0.1:6379/12'
CELERY_TIMEZONE = 'Asia/Shanghai'
# 配置批量偵錯程式
CELERYBEAT_SCHEDULER = 'djcelery.schedulers.DatabaseScheduler'
在主工程目錄新增 celery.py, 新增自動檢索 django 工程 tasks任務
celery.py
from __future__ import absolute_import
import os
from celery import Celery
# 設定環境變數
from HArtPro import settings
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'HArtPro.settings')
# 建立Celery物件
app = Celery('hart')
# 載入配置
app.config_from_object('django.conf:settings')
# 自動發現task的非同步任務
app.autodiscover_tasks(lambda :settings.INSTALLED_APPS)
當前 app 目錄下建立 tasks.py
from MArtPro.celery import app
from utils import redis_cache
@app.task
def advanceArt(artId, userId):
# 搶讀文章(artId 文章id, userId 當前使用者登入的Id)
print('使用者', userId, '正在搶讀', artId)
# 判斷當前搶讀的hash物件AdvanceArt長度是否達到5個
if redis_cache.hlen('AdvanceArt') >= 5:
return artId + '搶讀失敗'
redis_cache.hset('AdvanceArt', userId, artId)
return artId + '搶讀成功!'
views.py
from redis_ import rd # rd 物件
from art import tasks
def (request, artId):
# 搶讀
login_user = request.session.get('login_user')
if not login_user:
return JsonResponse({'status': 101,
'msg': '親,請先登入,再搶讀,謝謝!'})
# 判斷當前使用者是否已搶過
user_id =json.loads(login_user).get('id')
if redis_cache.hexists('AdvanceArt', user_id):
return JsonResponse({'status': 205,
'msg': '親,你只能搶一本'})
# 任務延遲執行
tasks.advanceArt.delay(artId, user_id)
return JsonResponse({'status': 201,
'msg': '正在搶讀...'})
def queryAdvance(request, artId):
# 查詢搶讀是否成功
login_user = request.session.get('login_user')
if not login_user:
return JsonResponse({'status': 101,
'msg': '親,請先登入,再檢視搶讀,謝謝!'})
user_id = json.loads(login_user).get('id')
artId = redis_cache.hget('AdvanceArt', user_id)
if artId:
art = Art.objects.get(id=artId.decode())
return JsonResponse({'status': 200,
'msg': '恭喜您,搶讀%s 成功'%art.title})
else:
if redis_cache.hlen('AdvanceArt')< 5:
return JsonResponse({'status': 202,
'msg': '正在搶讀...'})
else:
return JsonResponse({'status': 203,
'msg': '搶讀失敗, 請下次碰碰運氣!'})
前端通過定時器,每秒執行查詢函式
作者:rottengeek
轉載|原文連結:https://segmentfault.com/u/rottengeek
(如有侵權,請聯絡刪除)
最新公告通知
第 19 期【Python自動化運維入門】正在火熱招生中
第 8 期 【Python自動化運維進階】正在火熱招生中
相關文章
- Celery 進階使用
- Django Celery初識Django
- django中使用celeryDjango
- 在 Django 中使用 Celery 來進行耗時操作Django
- 在django中使用celeryDjango
- Django進階之路(一)Django
- Django專案中使用CeleryDjango
- django_celery_beat的部署Django
- python django與celery的整合PythonDjango
- celery 在django專案中使用Django
- django + redis + celery 非同步任務DjangoRedis非同步
- [Django高階之forms元件]DjangoORM元件
- Django高階之-快取Django快取
- Django教程(二)- Django檢視與網址進階Django
- 在django中使用celery(而不是djcelery)Django
- 2-django進階之日誌功能Django
- Python--Django:傳送郵箱 | 利用celery進行非同步處理PythonDjango非同步
- Django+Celery非同步傳送郵件Django非同步
- celery4+django2定時任務Django
- Django 使用 Celery 實現非同步任務Django非同步
- Python Django進階教程(三)(模型的高階用法)PythonDjango模型
- 進階剖析django通用類UpdateView(2張圖)DjangoView
- Django(41)詳解非同步任務框架CeleryDjango非同步框架
- Python Django進階教程(五)(session,Django使用者認證)PythonDjangoSession
- Python Django進階教程(四)(通用檢視)PythonDjango
- Django進階之路由層和檢視層Django路由
- 【Python】django-celery非同步任務佇列PythonDjango非同步佇列
- Python Django進階教程(一)(高階檢視和URL配置)PythonDjango
- javascript 進階之 - PromiseJavaScriptPromise
- IOS 進階之 WKWebViewiOSWebView
- 前端進階之困前端
- Pytest高階進階之Fixture
- Celery非同步排程框架(二)與Django結合使用非同步框架Django
- 快取更新-- 穿透/擊穿/雪崩 django-celery-flower Celery的應用///如何不重啟寫入快取穿透Django
- 高階前端的進階——CSS之flex前端CSSFlex
- Python Django進階教程(六)(快取機制,CSRF)PythonDjango快取
- JavaScript進階之繼承JavaScript繼承
- JavaScript進階之原型鏈JavaScript原型