1. 程式人生 > >Celery學習--- Celery 最佳實踐之與django結合實現異步任務

Celery學習--- Celery 最佳實踐之與django結合實現異步任務

tar load modules bin min sta 版本差異 status linux

django 可以輕松跟celery結合實現異步任務,只需簡單配置即可

同步執行和異步執行

技術分享圖片

技術分享圖片

註意:即使Celery的任務沒有執行完成,但是已經創建了任務ID。可以利用前臺的定時任務發送Ajax異步請求根據ID查詢結果

項目整合

項目的目錄結構:

技術分享圖片

項目前提: 安裝並啟動Redis

技術分享圖片

CeleryTest/settings.py

INSTALLED_APPS = [
   ...
 ‘app01‘,   # 註冊app
]
MIDDLEWARE = [
...
# ‘django.middleware.csrf.CsrfViewMiddleware‘,
      ...
]

STATICFILES_DIRS = (os.path.join(BASE_DIR, "statics"),)  # 現添加的配置,這裏是元組,註意逗號
TEMPLATES = [
   ...
   ‘DIRS‘: [os.path.join(BASE_DIR, ‘templates‘)],
]
# for celery
CELERY_BROKER_URL = ‘redis://192.168.2.105‘,
CELERY_BACKEND_URL = ‘redis://192.168.2.105‘,  # 用於Celery的返回結果的接收

CeleryTest/urls.py

from django.contrib import admin
from django.urls import path
from django.conf.urls import url, include
from app01 import views
urlpatterns = [
   url(r‘index/‘, views.Index),
   url(r‘task_res/‘, views.task_res),
]

app01/views.py

from django.shortcuts import render,HttpResponse
from app01 import tasks
# Create your views here.
# 視圖觸發Celery的用戶請求

def Index(request):
    print(‘進入Index...‘)
    res1 = tasks.add(5, 999)
    res = tasks.add.delay(5, 1000)
    print("res:", res)
    return HttpResponse(res)

# 前臺通過ID獲取Celery的結果
from celery.result import AsyncResult
def task_res(request):
    result = AsyncResult(id="5cf8ad07-8770-450e-9ccd-8244e8eeed19")
    # return HttpResponse(result.get())
    return HttpResponse(result.status)  # 狀態有Pending, Success, Failure等結果

app01/tasks.py 文件名必須為tasks.py

# 文件名必須為tasks.py,Djaogo才能發現Celery
from __future__ import absolute_import, unicode_literals
from celery import shared_task

# Django starts so that the @shared_task decorator (mentioned later) will use it:  
@shared_task    # Django的各個App裏都可以導入這個任務,否則只能在app01這個Django的App內使用
def add(x, y):
    return x + y

@shared_task
def mul(x, y):
    return x * y

@shared_task
def xsum(numbers):
    return sum(numbers)

CeleryTest/celery.py 文件名必須為celery.py

from __future__ import absolute_import, unicode_literals
import os
from celery import Celery

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

app = Celery(‘CeleryTest‘)

# Using a string here means the worker don‘t have to serialize
# the configuration object to child processes.
# - namespace=‘CELERY‘ means all celery-related configuration keys
#   should have a `CELERY_` prefix.
app.config_from_object(‘django.conf:settings‘, namespace=‘CELERY‘)

# Load task modules from all registered Django app configs.
app.autodiscover_tasks()
@app.task(bind=True)
def debug_task(self):
    print(‘Request: {0!r}‘.format(self.request))

CeleryTest/__init__.py

from __future__ import absolute_import, unicode_literals

# 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

__all__ = [‘celery_app‘]

Django前臺運行結果[獲取到了任務ID]:此時只有Django操作

技術分享圖片

Django後臺運行結果:此時只有Django操作

技術分享圖片

上傳文件到Linux服務器【Linux服務器需安裝好Django服務】

需要Ubuntu下安裝Django

pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple django

技術分享圖片

Linux下啟動Celery的worker: 【此時Win7下的Django配合Linux下的Celery執行】

omc@omc-virtual-machine:~/Celery/CeleryTest$  celery -A CeleryTest worker -l info

技術分享圖片

前臺瀏覽器觸發Django的views請求到Linux的Celery的worker進行結果處理

技術分享圖片

技術分享圖片

梳理一下整個的流程:

Win7下的Django配置好了和Celery的整合,連接上Redis。當有請求從瀏覽器發送過來的時候,從URL映射到Django的views裏面,在views裏面調用了tasks.add.delay(5, 1000)此時將任務請求存儲在了Redis裏面。後臺Linux下同樣也放了一份根Win7下同樣的工程[實際上只需要Celery的部分即可],進入Linux下的目錄後啟動Celery的worker,worker從Redis中取出任務去執行。而與此同時Django已經將任務的ID返回給了前臺,前臺可以根據任務ID返回的狀態判斷任務是否完成,完成後從Redis中獲取任務的結果進行頁面渲染即可,從而達到了異步的效果,就是前臺不用直接等待結果的返回,而是根據結果的狀態來獲取最後的結果。

Linux下安裝Django

pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple django

技術分享圖片

問題解決

20180430】一個由於Django版本和Celery版本差異引起的錯誤,導致一下午很失落,最後誤打誤撞解決,很失望

報錯信息:

KeyError: ‘backend‘

During handling of the above exception, another exception occurred:

技術分享圖片

settings.py ---Celery的配置錯誤:

  # for celery
CELERY_BROKER_URL = ‘redis://192.168.2.105‘,
CELERY_RESULT_BACKEND = ‘redis://192.168.2.105‘,  # 用於Celery的返回結果的接收

問題解決:

settings.py

# for celery
CELERY_BROKER_URL = ‘redis://192.168.2.105‘,
CELERY_BACKEND_URL = ‘redis://192.168.2.105‘,  # 用於Celery的返回結果的接收

Celery學習--- Celery 最佳實踐之與django結合實現異步任務