celery在Django中的集成使用


繼上回安裝和使用Redis之后,看看如何在Django中使用Celery。Celery是Python開發分布式任務列隊的處理庫。可以異步分布式地異步處理任務,也可定時執行任務等等。通常我們可以在Django執行一些比較耗時的任務(例如發郵件)和后台任務(例如爬蟲和更新服務器緩存)。

研究發現,在Django中使用有兩種方式:

1)使用django-celery應用;

2)直接使用Celery。

 

1、Celery方式的選擇

這里Celery的中間人,我采用Redis。也可以用Django自身和mongodb等。Celery的中間人你可以理解為在Celery執行過程中的數據支持。保存列隊記錄、執行記錄等等。安裝Redis,可參考Redis在CentOS和Windows安裝過程

這里還需要安裝celery-with-redis,執行命令:

  1. pip install celery-with-redis

該命令會自動安裝redis、celery、kombu、billiard、amqp、vine和celery-with-redis相關庫。

 

先說說django-celery的方式吧。這種方式就是通過manage.py啟動celery。通常先被提到的方案是不會采用。用pip安裝django-celery,在settings引用djcelery應用。再更新數據庫:

  1. python manage.py makemigrations djcelery
  2. python manage.py migrate djcelery

 

查看數據庫,會發現多了很多相關的表。

 

 

稍稍有些強迫症的我,不能接受這些表臟我的數據庫。另外djcelery還有個用途是在admin后台動態添加定時任務。這個功能也是比較雞肋,維護不方便而且可能造成各種不可預知的問題。

所以建議直接使用Celery管理Django中的任務。這種方式也是Celery官網推薦的方式,可看官網的示例:Celery官網(Celery 3.x版)

 

2、Django簡單項目准備

這里我也簡單做一個示例。

首先,確保celery和redis已經安裝好了,並且已經啟動了Redis服務。

另外,有個已經搭建好了Django項目。作為示例,簡單project和簡單app如下:

 

為了測試,一切從簡。views.py寫了一個響應方法:

 1 #coding:utf-8
 2 from django.shortcuts import render
 3 from django.http import HttpResponse
 4  
 5 from .models import Blog
 6 import json
 7  
 8 def home(request):
 9     data = list(Blog.objects.values('caption'))
10     return HttpResponse(json.dumps(data), content_type = 'application/json')

 

django項目的urls.py加了一條首頁的url路由設置:

1 #coding:utf-8
2 from django.conf.urls import url
3 from django.contrib import admin
4 from myapp.
5  
6 urlpatterns = [
7     url(r'^admin/', admin.site.urls),
8     url(r'^$', 'myapp.views.home', name='home')
9 ]

 

運行django項目:

 1 python manage.py runserver 

 

3、Django加入Celery

現打開首頁要執行一個收集訪客數據,發送郵件等操作。這是一個耗時任務,若放在home處理方法中執行,用戶打開首頁會很慢。用戶體驗不好,很可能不會等到頁面打開。

通常這個耗時任務可以多線程處理或者異步處理。我們模擬一個耗時任務,丟給Celery異步處理。

先模擬耗時任務,打開views.py,修改如下:

 1 #coding:utf-8
 2 from django.shortcuts import render
 3 from django.http import HttpResponse
 4  
 5 from .models import Blog
 6 import json
 7 import time
 8  
 9 def sendmail(email):
10     print('start send email to %s' % email)
11     time.sleep(5) #休息5秒
12     print('success')
13     return True
14  
15 def home(request):
16     #耗時任務,發送郵件
17     sendmail('test@test.com')
18  
19     #其他行為
20     data = list(Blog.objects.values('caption'))
21     return HttpResponse(json.dumps(data), content_type = 'application/json')

如此一來,至少需要再多等待5秒,才可以打開網頁。

打開settings.py所在的文件夾,新建celery.py文件。加入如下代碼(注意,因為celery-with-django版本限制,我安裝的celery版本為3.1.25。可能celery4.x的版本代碼不同):

 1 #coding:utf-8
 2 from django.shortcuts import render
 3 from django.http import HttpResponse
 4  
 5 from .models import Blog
 6 import json
 7 import time
 8  
 9 def sendmail(email):
10     print('start send email to %s' % email)
11     time.sleep(5) #休息5秒
12     print('success')
13     return True
14  
15 def home(request):
16     #耗時任務,發送郵件
17     sendmail('test@test.com')
18  
19     #其他行為
20     data = list(Blog.objects.values('caption'))
21     return HttpResponse(json.dumps(data), content_type = 'application/json')

 

這個文件還沒被加載,接着打開settings.py同個目錄下的__init__.py文件。讓運行該Django項目的時候,加載該文件配置Celery。修改代碼如下:

1 #coding:utf-8
2 from __future__ import absolute_import, unicode_literals
3  
4 #引入celery實例對象
5 from .celery import app as celery_app

 

還需在settings.py中設置celery,尤其是中間人的設置。若不設置中間人,會提示無法連接中間人的錯誤。在settings.py文件中添加如下設置:

 1 #celery settings
 2 #celery中間人 redis://redis服務所在的ip地址:端口/數據庫號
 3 BROKER_URL = 'redis://localhost:6379/0'
 4 #celery結果返回,可用於跟蹤結果
 5 CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'
 6  
 7 #celery內容等消息的格式設置
 8 CELERY_ACCEPT_CONTENT = ['application/json',]
 9 CELERY_TASK_SERIALIZER = 'json'
10 CELERY_RESULT_SERIALIZER = 'json'
11  
12 #celery時區設置,使用settings中TIME_ZONE同樣的時區
13 CELERY_TIMEZONE = TIME_ZONE

 

4、把耗時任務丟給celery處理

上面views.py中有個耗時任務sendmail。在myapp應用中新建文件tasks.py,將sendmail方法剪切到該文件中並用定義為celery任務。tasks.py文件如下代碼:

 1 #coding:utf-8
 2 from celery.decorators import task 
 3 import time
 4  
 5 @task
 6 def sendmail(email):
 7     print('start send email to %s' % email)
 8     time.sleep(5) #休息5秒
 9     print('success')
10     return True

 

在原有的方法上加上celery裝飾器task。或者也可以通過前面添加的celery_app給sendmail方法加裝飾器:

 1 #coding:utf-8
 2 #myproject是當前django的項目名
 3 from myproject import celery_app
 4 import time
 5  
 6 @celery_app.task
 7 def sendmail(email):
 8     print('start send email to %s' % email)
 9     time.sleep(5) #休息5秒
10     print('success')
11     return True

 

另外原先的views.py修改如下:

 1 #coding:utf-8
 2 from django.shortcuts import render
 3 from django.http import HttpResponse
 4  
 5 from .models import Blog
 6 from .tasks import sendmail #引用tasks.py文件的中sendmail方法
 7 import json
 8  
 9 def home(request):
10     #耗時任務,發送郵件(用delay執行方法)
11     sendmail.delay('test@test.com')
12  
13     #其他行為
14     data = list(Blog.objects.values('caption'))
15     return HttpResponse(json.dumps(data), content_type = 'application/json')

5、本地啟動celery並測試

啟動celery之前,確保已經安裝redis和啟動redis服務,可參考Redis在CentOS和Windows安裝過程

本地開發環境運行redis-cli看是否可以正常連接,若不行,再手工執行redis-server命令並保持窗口即可。

 

 

接着,啟動celery worker。這個worker是用於異步執行任務的“工作者”。進入manage.py文件所在的目錄,執行如下命令:

 1 Celery -A myproject worker -l info 

 

出現如下窗口和消息,則正常執行。

 

 

celery worker會掃描django項目中有哪些task任務,並加入進來。

最后,再啟動django服務器。這個大家熟悉的python manage.py runserver。

打開首頁,可以發現沒有5秒等待立即得到首頁內容。查看celery worker,可看到執行sendmail方法的消息。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM