如何使用Django+Celery+Redis来执行耗时任务
环境需求
- Python ❨2.7, 3.4, 3.5❩
- Celery version 4.0
- Redis 4.0.9
- 虚拟机安装Linux Ubuntu(或其他如:CentOS)用于安装redis-server
本文将不再赘述如何安装虚拟机和设置redis-server
什么是Celery?
Celery是一个简单,可靠,易配置的分发系统,通常用来处理大量消息队列。Celery本身提供了非常强大的功能,可以用来作为一个任务队列系统来实时处理任务,或者也可以设置定时任务。本文将一步步说明,如何用Django设置一个异步任务——发送电子邮件
基本环境配置(Mac os/Linux)
安装virtualenv
$ pip install virtualenv
新建一个文件夹
比如:取名为example,在命令行中输入
$ mkdir example
$ cd ~/Desktop/example
激活虚拟环境
$ virtualenv venv
$ source venv/bin/activate
(venv)example$ (表示已进入虚拟环境)
(windows): venv\Scripts\activate
安装Django,启动project和app
(venv)example$ pip install django
(venv)example$ django-admin startproject example . # 加. 表示在当前目录下创建project
(venv)example$ django-admin startapp send_email
进一步配置Django,并安装Celery
建立celery.py
放在example/example/celery.py中
此时项目结构图:
并复制以下代码到celery.py中,此处example即使你的项目名
example/example/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', 'example.settings')
app = Celery('example')
# Using a string here means the worker doesn'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')
# 自动添加所有app中的task.py中的任务
app.autodiscover_tasks()
@app.task(bind=True)
def debug_task(self):
print('Request: {0!r}'.format(self.request))
安装celery和redis库
(venv)example$ pip install celery
(venv)example$ pip install redis
在example/example/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',)
设置views.py和路由urls.py
在example/send_email/views.py中,代码如下:
from django.shortcuts import render
from django.http import HttpResponse
def index(request):
return HttpResponse('Done')
在example/send_email/urls.py中,代码如下:(需先新建一个urls.py文件)
from django.contrib import admin
from django.urls import path
from . import views
urlpatterns = [
path('', views.index, name='index'),
]
在example/example/urls.py中,代码如下:(主路由)
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('',include('send_email.urls')),
]
在example/example/settomg.py中的INSTALLED_APPS加入send_email
INSTALLED_APPS = [
# ...省略...
'send_email',
]
此时可以尝试跑一下django,看是否能正常运行
(venv)example$ python manage.py runserver
请确保虚拟环境已激活,命令行或bash前面有(venv)字样,否则输入source venv/bin/activate (windows: venv\Scripts\activate)
浏览器中输入:http://127.0.0.1:8000/
应该就可以看到Done的字样了。
配置celery和redis
Redis
首先本文跳过了在虚拟机中安装redis-server的操作,整个过程很简单,大概几分钟就可以配置好。
此处redis的作用为存储我们celery的任务队列(broker)。
配置好redis-server后,在example/example/setting.py中加入
如果你的redis-server配置了密码,请按照下方注释中的格式设置
# redis://:密码@x.x.x.x:port
CELERY_BROKER_URL = 'redis://192.168.1.108:6379'
CELERY_ACCEPT_CONTENT = ['application/json']
CELERY_TASK_SERIALIZER = 'json'
建立tasks.py
新建一个tasks.py,放入example/send_email/task.py中
这个文件中,就可以定义我们要执行的异步任务了,比如发邮件。
from celery import shared_task
from django.core.mail import send_mail
@shared_task
def task_send_email():
send_mail('Celery task', # 邮件标题
'Hello Django', # 邮件正文
'xxxxxx@qq.com', # 发件人
['xxxxxx@qq.com']) # 收件人(一个list)
return 'Email sent'
在send_email/views.py中创建函数来执行celery任务
from django.http import HttpResponse
from .tasks import task_send_email
# Create your views here.
def index(request):
task_send_email.delay()
return HttpResponse('Done')
设置example/example/setting.py邮件相关参数
此处我采用了QQ邮箱,相关参数如下。
EMAIL_HOST = 'smtp.qq.com'
EMAIL_HOST_USER = 'xxxxxxx@qq.com'
EMAIL_HOST_PASSWORD = 'yourpassword'
EMAIL_USE_SSL = True
EMAIL_USE_TLS = False
EMAIL_PORT = 465
如果是其他邮箱,设置可能会有些许区别。
启动celery和django
celery
启动命令:
(venv)example$ celery -A example worker -l info
看到如下信息表示启动成功
-------------- celery@supermando.lan v4.4.7 (cliffs)
--- ***** -----
-- ******* ---- macOS-10.13.6-x86_64-i386-64bit 2020-09-23 11:48:59
- *** --- * ---
- ** ---------- [config]
- ** ---------- .> app: example:0x1043b4d00
- ** ---------- .> transport: redis://192.168.1.108:6379//
- ** ---------- .> results: disabled://
- *** --- * --- .> concurrency: 8 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
-------------- [queues]
.> celery exchange=celery(direct) key=celery
[tasks]
. example.celery.debug_task
. send_email.tasks.task_send_email #此处提示我们的task_send_email已经在任务列表中了
[2020-09-23 11:48:59,659: INFO/MainProcess] Connected to redis://192.168.1.108:6379//
[2020-09-23 11:48:59,668: INFO/MainProcess] mingle: searching for neighbors
[2020-09-23 11:49:00,689: INFO/MainProcess] mingle: all alone
新开一个terminal或(命令提示行),cd 到项目目录,激活虚拟环境,开启django服务
$ source venv/bin/activate
(venv)example$ python manage.py runserver
测试celery
访问 http://localhost:8000
此时浏览器应该是出现一个单词
Done
然后打开我们的电子邮件收件箱,确认是否收到邮件,如果成功收到邮件,恭喜你,现在你可以使用Celery来处理异步任务了。
github: https://github.com/hguitar/django_celery_redis_async_tasks