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函數一樣返回了,所以還是會跳出循環。

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