django-celery定時任務以及非同步任務and伺服器部署並且執行全部過程
Celery
應用Celery之前,我想大家都已經瞭解了,什麼是Celery,Celery可以做什麼,等等一些關於Celery的問題,在這裡我就不一一解釋了。
應用之前,要確保環境中添加了Celery包。
pip install celery
pip install dajngo-celery
安裝完成之後我們還需要安裝,Redis or RabbitMQ 需要用到它們來建立訊息佇列來完成收,發任務。
RabbitMQ使用者手冊:
Redis中文官網:
用以上兩種作為訊息處理佇列都可以,今天我們來使用Redis來作為佇列。
本人是用Windows來測試,後邊有Linux安裝方法。
開啟連結之後,出現如下頁面,然後點選 releases
進入到下載頁面之後,找到需要下載的版本,測試版本(3.0.500)然後點選版本名稱進入當前版本頁面。
下載之前需要注意的是,紅框中,第一個msi字尾的是微軟格式的安裝包,第二個zip是壓縮包。
下載完成之後,雙擊msi檔案。
安裝完成之後,以便從程式後續能夠正常工作,新增訪問密碼,
開啟安裝目錄,找到 redis.windows-service.conf 配置檔案,用文字編輯器開啟,找到 requirepass字樣的地方,新增一行 requirepass 密碼。 這是訪問redis時需要的密碼。一般情況下是可以不用設定的,但是建議還是設定一下。(我用Notepad++開啟的)位置:386
配置完成之後,點選"開始>右擊"計算機">"管理", 在左側找到"計算機管理(本地)">服務和應用程式>服務,再在右側找到Redis名稱的服務,檢視啟動狀態,沒有啟動則手動啟動,一般情況下服務該正常運行了。
Redis服務啟動過程中,報位置錯誤的情況下,解決辦法如下:
1、開啟redis安裝目錄找到redis.windows.conf檔案拉到底部,新增 maxmemory 209715200
2、新增完成之後儲存退出,開啟終端,用命令啟動, redis-service.exe redis-windows.conf
3、啟動過程中在報錯,錯誤資訊:
[22420] 11 Oct 11:46:23.351 #Server started, Redis version 3.0.500 [22420] 11 Oct 11:46:23.355 # Can't handle RDB format version 7 [22420] 11 Oct 11:46:23.355 # Fatal error loading the DB: Invalid argument. Exiting.
解決辦法:
刪除所有的dump.rdb檔案,重啟新啟動, redis-service.exe檔案,報錯原因,可能是rdb檔案版本過高或者過低所導致問題出現,
啟動成功介面:
redis啟動成功之後就不要關閉,應為celery是基於redis來收發任務的, 需要用到redis的佇列。
環境到此安裝完成之後,開始寫個簡單的非同步任務。
Celery 非同步任務
新建立一個Django專案,新增一個應用。
django-admin startproject celery_sq
新建應用
python manage.py startapp app
專案初始化完成之後,開啟settings.py檔案
一定要將celery匯入進去,才可以使用。緊接著匯入需要用到的模組。
from celery.schedules import crontab from celery.schedules import timedelta匯入
在settings檔案拉到底部,新增以下程式碼。
import djcelery djcelery.setup_loader() BROKER_URL = 'redis://127.0.0.1:6379/' CELERY_IMPORTS = ('app.tasks') CELERY_TIMEZONE = 'Asia/Shanghai' CELERYBEAT_SCHEDULER = 'djcelery.schedulers.DatabaseScheduler'底部新增程式碼
以上程式碼新增完成之後再同級目錄下建立 celery.py
from __future__ import absolute_import, unicode_literals # -*- coding: utf-8 -*- __author__ = 'YongCong Wu' # @Time : 2018/10/9 15:52 # @Email : : [email protected] import os 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', 'celery_sq.settings') app = Celery('celery_sq') # 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') # Load task modules from all registered Django app configs. app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) @app.task(bind=True) def debug_task(self): print('Request: {0!r}'.format(self.request))celery.py
在app目錄下新增tasks.py檔案, 注意:一個應用下只能新增一個tasks.py 一個py一遍可寫多個任務。
from __future__ import absolute_import # -*- coding: utf-8 -*- __author__ = 'YongCong Wu' # @Time : 2018/10/9 16:10 # @Email : : [email protected] from celery_sq.celery import app @app.task def add(x, y): return x + ytasks.py
新增完成之後,在app同級目錄下的views檔案裡邊新增函式。
from django.shortcuts import render, HttpResponse # Create your views here. from .tasks import add import json def add_handler(request): x = request.GET.get('x', 1) y = request.GET.get('y', 1) result = add(int(x), int(y)) return HttpResponse(json.dumps({'result': result}))views.py
新增urls.py
# -*- coding: utf-8 -*- __author__ = 'YongCong Wu' # @Time : 2018/10/10 14:46 # @Email : : [email protected] from django.conf.urls import include, url from django.contrib import admin from app import views urlpatterns = [ url(r'^add/', views.add_handler), ]urls.py
app 中的url新增完成之後需要在celery_sq目錄下的urls.py中新增。
from django.conf.urls import include, url from django.contrib import admin urlpatterns = [ url(r'^admin/', include(admin.site.urls)), url(r'^home/', include('app.urls')), # 新增這個 ]celery_sq/urls.py
新增完成之後就開始測試我們的專案,現將專案執行起來。
python manage.pu runserver
專案啟動完成之後,重新開啟一個終端,進入專案目錄,啟動django celery 服務。
python manage.py celery worker --loglevel=info
見到這個介面,就說明django celery已經啟動成功了,接下來就開始測試我們的非同步任務了。
測試地址埠可自行修改,根據自己埠來設定: http://127.0.0.1:9000/home/add/?x=5&y=5
Celery定時任務
現在每家公司,有各種各樣的需求,有的需要定時去查詢資料等等,一些定時的功能。接下來,我們就用Celery來完成一個定時寫入txt檔案的一個任務。
app/tasks.py檔案新增以下程式碼。
from celery import shared_task @shared_task def hello_world(): with open("output.txt", "a") as f: f.write("hello world") f.write("\n")tasks.py
在settings.py下新增
CELERYBEAT_SCHEDULE = { # 定時器策略 # 定時任務一: 每隔30s執行一次 u'測試定時器1': { "task": "app.tasks.tsend_email", # "schedule": crontab(minute='*/2'), # or 'schedule': timedelta(seconds=3), "schedule": timedelta(seconds=30), "args": (), }, }定時
此時tasks.py檔案裡邊有一個定時tasks。
引數定義:
days 天
seconds 秒
microseconds 微秒
milliseconds 毫秒
minutes 分
hours 小時
timedelta引數含義
month_of_year 月份
day_of_month 日期
day_of_week 周
hour 小時
minute 分鐘
crontab引數含義
定時任務新增完成之後,啟動celery beat, celery啟動了一個beat程序一直在不斷的判斷是否有任務需要執行。
celery -A celery_sq beat -l info
重新開啟終端,輸入以上命令啟動 celery beat, 啟動成功之後看到如下頁面。
任務成功執行之後狀態
到此為止,在windows下,測試非同步任務和定時任務已經完成,那麼有個問題,在windows下執行一下celery需要開啟這麼多的終端視窗,哪用linux部署專案的時候該怎麼辦呢,接下來,我們就在linux下部署。我們用守護程序的方式來完成。
Linux下部署django-celery
Linux預設Python環境是2.7,需要自行下載Pyhton3.5。(安裝過程自行百度)
linux下,我們一般用守護程序的方式來啟動 Celery ,不然總不能在開啟很多視窗一個視窗啟動一個beat等等吧。
在linux下使用supervisor來守護程序。
supervisor官網:
安裝Redis:
wget http://download.redis.io/releases/redis-2.8.3.tar.gz
安裝完成之後需要解壓,編譯。依次按照以下命令執行。
tar xzf redis-2.8.3.tar.gzcd redis-2.8.3make && make install
安裝supervisor
pip install supervisor
supervisor配置
我們使用echo_supervisord_conf命令來得到supervisor配置模板,開啟終端shell輸入以下命令。
echo_supervisord_conf > supervisord.conf
接下來編輯 supervisord.conf檔案
vim supervisord.conf
修改include分發ini檔案目錄。
配置完成之後建立conf.d目錄
mkdir conf.d
建立完成之後進入目錄,建立ini檔案將以下配置寫入檔案中。
測試新增ini檔案是否讀取。
在任意目錄下建立hello.py檔案,新增以下程式碼,來進行測試。
import time import sys while True: print("test data\n") sys.stdout.flush() time.sleep(1)
新增完成之後儲存,用 python 檔名稱 來執行py檔案是否出錯。正確結果:
測試完成之後開始為hello.py新增程序守護。
進入conf.d目錄新增 hello.ini檔案。將以下配置寫入檔案。
[program:hello] 名字隨意,不要重複 command=python /home/hello.py stdout_Logfile=/home/celery_log/hello.log stderr_logfile=/home/celery_log/hello_error.log
執行supervisord
supervisord -c /home/supervisor/supervisord.conf
執行hello程序
supervisordctl -c /home/supervisor/supervisord.conf 執行全部 supervisordctl -c /home/supervisor/supervisord.conf start heelo 指定執行 supervisordctl -c /home/supervisor/supervisord.conf stop heelo 指定停止 引數: start status stop restart 啟動,狀態, 停止, 重啟
以上圖片是啟動成功之後的狀態。
測試完成之後就開始配置Redis。
新增redis.ini檔案,將以下內容新增。
[program:redis] command=/home/redis-4.0.1/src/redis-server autostart=true autorestart=true startsecs=3 stdout_Logfile=/home/celery_Log/redis.log 標準日誌輸出 stderr_logfile=/home/celery_log/redis_error.log 錯誤日誌輸出
新增完成之後需要使用以下命令來載入程序。
supervisorctl reload
由於 supervisor 管理的程序不能設定為 daemon 模式,故如果 Redis 無法正常啟動,可以檢視一下 Redis 的配置,並將daemonize
選項設定為 no。
daemonize no
到檔案的地步新增如下資訊
[program:celery] # 啟動命令入口 command=/var/www/newweb/venv/bin/celery worker -A celery_worker.celery --loglevel=info # 命令程式所在目錄 directory=/var/www/newweb/ # 執行命令的使用者名稱 user=root autostart=true autorestart=true # 日誌地址 stdout_logfile=/var/log/newymw2.0/supervisor/newymw2.0_celery.log
另外在celery.worker下設定beat定時任務的程序
[program:celery.beat] ;指定執行目錄 directory=/home/xxx/webapps/yshblog_app/yshblog ;執行目錄下執行命令 command=celery -A yshblog worker --loglevel info --logfile celery_beat.log ;啟動設定 numprocs=1 ;程序數 autostart=true ;當supervisor啟動時,程式將會自動啟動 autorestart=true ;自動重啟 ;停止訊號 stopsignal=INT
worker和beat都設定好之後就可以配置redis了。
[program:redis] ;指定執行目錄 directory=~/webapps/yshblog_app/lib/redis-3.2.8/ ;執行命令(redis-server redis配置檔案路徑) command=redis-server redis.conf ;啟動設定 numprocs=1 ;程序數 autostart=true ;當supervisor啟動時,程式將會自動啟動 autorestart=true ;自動重啟 ;停止訊號 stopsignal=INT
啟動supervisord
supervisord -c /home/supervisor/supervisor.conf
檢視程序狀態
supervisorctl -c /home/supervisor/supervisor.conf status all
載入supervisord,在新新增程序的情況下使用載入,新新增一個,載入一次。
supervisorctl -c /home/supervisor/supervisor.conf reload
執行測試celery過程中如果出現如下錯誤(celery不能用root使用者來啟動),按照以下步驟新增,即可解決
測試命令:
celery -A celery_sq worker -l info
錯誤資訊:
Running a worker with superuser privileges when the worker accepts messages serialized with pickle is a very bad idea! If you really want to continue then you have to set the C_FORCE_ROOT environment variable (but please think about this before you do). User information: uid=0 euid=0 gid=0 egid=0
解決辦法:
celery.py新增如下程式碼 from celery import Celery, platforms platforms.C_FORCE_ROOT = True
測試成功頁面
測試成功之後開始測試beat
測試beat命令:
celery -A celery_sq beat -l info
測試成功頁面:
成功之後守護程序就是這個樣子的。
[program:redis] command=/home/redis-4.0.1/src/redis-server autostart=true autorestart=true startsecs=3 stdout_Logfile=/home/celery_log/redis.log stderr_logfile=/home/celery_log/redis_error.logredis.ini
[program:celeryworker] directory=/root/.pyenv/versions/Celery_prj/celery_sq command=celery -A celery_sq worker -l info autostart=true autorestart=true stdout_logfile=/home/celery_log/celery_worker.log stderr_logfile=/home/celery_log/celery_worker_error.logworker.ini
[program:celerybeat] directory=/root/.pyenv/versions/Celery_prj/celery_sq command=celery -A celery_sq beat -l info autostart=true autorestart=true stdout_logfile=/home/celery_log/celery_beat.log stderr_logfile=/home/celery_log/celery_beat_error.logbeat.ini
到此為止,windows以及Linux下django-celery守護程序以及配置全部完成, 以上由本人全部親測,一步一步寫進部落格,如有問題,請及時提出。見到第一時間修改。/抱拳