django開發傻瓜教程-3-celer
- 2020 年 1 月 20 日
- 筆記
Ref:
https://www.jianshu.com/p/6f8576a37a3e
https://blog.csdn.net/Demo_3/article/details/78119951
https://blog.csdn.net/spur_man/article/details/79550917
https://my.oschina.net/37Y37/blog/1920149
http://docs.jinkan.org/docs/celery/getting-started/next-steps.html
https://www.ctolib.com/topics-130539.html#
為什麼選擇Celery
當前的需求是:我用form從前端拿到了提交的數據,由於需要處理一點時間(也許很多用戶同時提請求呢)雖然感覺暫時想多了=.=
如果處理時間過長,那麼一方面頁面可能會超時,另一方面,用戶等待太久也是不合適的。所以現在希望,在用戶提交數據後,立刻就
能收到一個回復(比如說task ID),等到任務結束後,通知用戶,用這個ID就可以獲取結果(當然可以是伺服器靠這個ID來輸出結果)。
我也考慮過用ajax直接部分刷新頁面,但是感覺對於長時間的並發任務,可能不是很合適(看到的ajax例子都是很簡單的,不是很懂是不是不適合複雜的計算邏輯?)。總之,為了以後的發展,還是學一下水芹菜吧。
概念

Celery 的基本架構採用典型的生產者—消費者模式,主要由三部分組成:broker(消息隊列)、workers(消費者:處理任務)、backend(存儲結果)。Celery自己不提供消息服務,但是可以和提供消息服務的中間件集成。這裡推薦的broker有RabbitMQ(官網推薦)和Redis。Workers可以並發地運行在分散式的節點上。
實際應用時,用戶從 Web 前端發起一個請求,然後將請求所要處理的任務丟入 broker中,由空閑的 worker 去處理,處理的結果會暫存在後台資料庫 backend 中。
處理場景
非同步任務處理:例如給註冊用戶發送短消息或者確認郵件任務。
大型任務:執行時間較長的任務,例如影片和圖片處理,添加水印和轉碼等,需要執行任務時間長。
定時執行的任務:支援任務的定時執行和設定時間執行。例如性能壓測定時執行。
安裝
pip install celery

為了讓celery中執行任務的結果返回Django,再裝一個
sudo pip install django-celery-results
使用redis做broker和backend,安裝:
sudo apt-get install redis sudo pip install redis
如果apt-get有錯誤,請用下面的命令
sudo apt-get install redis --fix-missing
開啟redis服務
redis-server
報錯

我就知道不會一帆風順的:)
解決:1. 找到redis-server進程,kill

2. 接著發現redis-server進程仍然存在,殺不掉:)
所以使用停止服務的命令。必要的話要用sudo。
/etc/init.d/redis-server stop
然後再重啟redis-service即可

現在正式來寫Celery了。首先看一下目錄結構:

配置階段先改celery.py和__init__.py
# Celery.py from __future__ import absolute_import, unicode_literals import os from celery import Celery, platforms # set the default Django settings module for the 'celery' program. os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'probe.settings') app = Celery('probe') # 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() # Allow root user run celery platforms.C_FORCE_ROOT = True @app.task(bind=True) def debug_task(self): print('Request: {0!r}'.format(self.request))
__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']
然後進入根目錄
celery worker -A probe -l info

你以為這樣就可以了?報錯:

這是因為我們的水芹找不到redis啊:)所以要修改上面的celery.py
# redis是broker和backend app = Celery('probe', backend='redis', broker='redis://localhost')

現在來配置一下celery。上面的修改暫時取消,我們統一在settings.py里配置celery。
CELERY_BROKER_URL = 'redis://localhost:6379' CELERY_ACCEPT_CONTENT = ['json'] CELERY_TASK_SERIALIZER = 'json' CELERY_RESULT_BACKEND = 'redis' CELERY_TIMEZONE = 'Asia/Shanghai' CELERYD_MAX_TASKS_PER_CHILD = '1'
# celery在長時間運行後可能出現記憶體泄漏,需要添加這個配置,表示每個worker執行了多少個任務就死掉
# INSTALLED_APPS里再添加一個'django_celery_results'
然後migrate一下變化
python manage.py migrate django_celery_results
現在來真正寫任務了:task.py
這個task.py在每個app下都要有,而且名稱不能改變。
from __future__ import absolute_import, unicode_literals from celery import shared_task @shared_task def longtime_test(): # 在這裡寫操作
然後在views.py里(我這裡是把design2.py和主頁design-post綁在一起的,所以我寫到design2.py里去)
longtime_test.delay()
補一刀:
在design2.py里,我這麼寫(省略其他)這裡只是簡單測試一下:
import task def design_post(request): ... if request.POST: result = task.longtime_test.delay(ctx['target_definition'], ctx['target_species']) while True: if result.ready(): print "celery fried!" break; ...
事實上我第一次遇到了報錯

當時寫的是from task import longtime_test
我改成上面的寫法之後,重啟celery,就沒有報錯:celery正確輸出字元串(畢竟我只做了字元串連接啊攤手)

而且django後台這裡也正確回饋了(黃色標識)紅色的是之前報錯狀態的顯示。因為longtime_test函數一樣返回了,所以還是會跳出循環。

好了我現在要去寫業務程式碼了,配置方面的任務暫時告一段落:)