详解Django中异步任务之django-celery


Posted in Python onNovember 05, 2020

Celery文档参考:http://docs.jinkan.org/docs/celery/

参考文章:https://3water.com/article/158046.htm

Django中异步任务---django-celery

Celery简单介绍:

celery使用场景:

  1. 耗时任务定时任务
  2. 请求结果不怎么重要的
  • 耗时任务比如:发送短信验证码我们可以先发送给客户任务状态(请求成功或失败)
  • 请求结果重要的建议使用django实现 比如:支付

首先简单介绍一下,Celery 是一个强大的分布式任务队列,它可以让任务的执行完全脱离主程序,甚至可以被分配到其他主机上运行。我们通常使用它来实现异步任务(asynctask)和定时任务(crontab)。它的架构组成如下图

详解Django中异步任务之django-celery

Celery 主要包含以下几个模块:

任务模块 Task

包含异步任务和定时任务。其中,异步任务通常在业务逻辑中被触发并发往任务队列,而定时任务由 Celery Beat 进程周期性地将任务发往任务队列。

消息中间件 Broker

Broker,即为任务调度队列,接收任务生产者发来的消息(即任务),将任务存入队列。Celery 本身不提供队列服务,官方推荐使用 RabbitMQ 和 Redis 等。

任务执行单元 Worker

Worker 是执行任务的处理单元,它实时监控消息队列,获取队列中调度的任务,并执行它。

任务结果存储 Backend

Backend 用于存储任务的执行结果,以供查询。同消息中间件一样,存储也可使用 RabbitMQ, Redis 和 MongoDB 等。

p>django-celery


首先需要统一一下使用的环境,以为如果redis的版本过高会报错

详解Django中异步任务之django-celery

解决方法:建议降低redis版本

推荐版本

Django == 2.2.6

django-celery == 3.3.1

django-redis == 4.11.0

redis == 2.10.6

celery == 3.1.26.post2

依赖安装:pip install .....详解Django中异步任务之django-celery人都知道

1.修改setting.py django配置文件,增加如下:

import djcelery ###导包
djcelery.setup_loader() ###
BROKER_URL = 'redis://127.0.0.1:6379/2'
# BROKER_URL='redis://192.168.217.77:16379/2' #任何可用的redis都可以,不一定要在django server运行的主机上
CELERYBEAT_SCHEDULER = 'djcelery.schedulers.DatabaseScheduler' ### 
INSTALLED_APPS = [
 ...
 "djcelery",	# 加入djcelery应用
 ...
 
]
CELERY_TIMEZONE='Asia/Shanghai' #并没有北京时区,与下面TIME_ZONE应该一致
TIME_ZONE='Asia/Shanghai' #

开头增加如上配置文件,根据实际情况配置redis的地址和端口,时区一定要设置为Asia/Shanghai。否则时间不准确回影响定时任务的运行。

上面代码首先导出djcelery模块,并调用setup_loader方法加载有关配置;注意配置时区,不然默认使用UTC时间会比东八区慢8个小时。其中INSTALLED_APPS末尾添加两项,分别表示添加celery服务和自己定义的apps服务。

2.创建Celery所需的数据表

python manage.py migrate
#如若不成功可以尝试一下命令语句
#python manage.py syncdb

3.创建task

详解Django中异步任务之django-celery

stasks.py

# -*- coding: utf-8 -*-
import json, time
from syl.settings import ALY_ACCESSKEY_ID, ALY_ACCESSKEY_SECRET
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.request import CommonRequest
from celery import task
 
 
# 阿里云短信验证码
 
@task
def Celery_Send_Sms(phone, data):
 client = AcsClient(ALY_ACCESSKEY_ID, ALY_ACCESSKEY_SECRET, 'cn-hangzhou')
 request = CommonRequest()
 request.set_accept_format('json')
 request.set_domain('dysmsapi.aliyuncs.com')
 request.set_method('POST')
 request.set_protocol_type('https') # https | http
 request.set_version('2017-05-25')
 request.set_action_name('SendSms')
 request.add_query_param('RegionId', "cn-hangzhou")
 request.add_query_param('PhoneNumbers', phone)
 request.add_query_param('SignName', "美多商城")
 request.add_query_param('TemplateCode', "SMS_205397849")
 request.add_query_param('TemplateParam', data)
 response = client.do_action(request)
 time.sleep(10)
 print(str(response, encoding='utf-8'))
 res = json.loads(str(response, encoding='utf-8'))
 
#celery运行命令
# python manage.py celery worker --loglevel=info
  1. settings.py中的djcelery.setup_loader()运行时, Celery便会查看所有INSTALLED_APPS中app目录中的tasks.py文件, 找到标记为task的function, 并将它们注册为celery task.
  2. 在执行djcelery.setup_loader()时, task是以INSTALLED_APPS中的app名, 加.tasks.function_name注册的
  3. 一次需要注意 在impprt task时, 需要保持一致
  4. 如果我们由于python path不同而使用不同的引用方式时(例如在tasks.py中使用from myproject.myapp.tasks import add形式), Celery将无法得知这是同一task, 因此可能会引起奇怪的bug。

让任务变成异步

例如我们希望在用户发出request后异步执行该task, 马上返回response, 从而不阻塞该request, 使用户有一个流畅的访问过程. 那么, 我们可以使用.delay。

详解Django中异步任务之django-celery

views.py

import re
import random
from rest_framework.permissions import AllowAny
from django_redis import get_redis_connection
from rest_framework.views import APIView
from rest_framework.response import Response
# from utils.MyBaseView import send_message, Send_Sms
from verifications.stasks import Celery_Send_Sms
 
# 用户注册短信验证码
class SmsCodeView(APIView):
 '''使用apiview的限流'''
 # 1. 所有人可以访问
 permission_classes = (AllowAny,)
 
 def post(self, request):
  # 1. 获取参数
  phone = request.data.get('phone') # 手机号
  image_code = request.data.get('image_code') # 字符串验证码
  image_code_uuid = request.data.get('image_code_uuid') # 前端生成的uuid,是redis中图片验证码的key
 
  # 2. 检查参数
  if not all([phone, image_code, image_code_uuid]):
   return Response({'code': 400, 'msg': '参数不全'})
 
  # 检查手机号是否正确
  if not re.match(r'^1[3456789]\d{9}$', phone):
   return Response({"code": 999, "msg": "手机号码不正确"})
 
  # 3. 检查是否发送
  redis_client = get_redis_connection('img_code') # 连接redis数据库
  # phone_exists = redis_client.get(phone)
  # if phone_exists:
  #  return Response({"code": 999, "msg": "频繁发送, 请稍后再试"})
 
  # 4.检查图片验证码是否合法
  redis_image_code = redis_client.get(image_code_uuid) # 字符串验证码
  if redis_image_code:
   # bytes 转成 string
   redis_image_code = redis_image_code.decode() # 把uuid解码
 
  # 比较用户提供的图片内容是否和redis中保存的一致
  if image_code.upper() != redis_image_code:
   return Response({'code': 999, 'msg': '图片验证码不正确'})
  # 5. 发送
  code = '%06d' % random.randint(100000, 999999) # 随机6位验证码
  print('code===============================================', code)
  # 使用容联云短信验证码
  # send_resp = send_message(phone, (code, "5"))
 
  # 使用阿里云短信验证码
  data = {'code': code}
  # send_resp = Send_Sms(phone, data)
  # 使用celery异步发送短信
  Celery_Send_Sms.delay(phone, data) #delay是注册为celery异步任务的关键点
  # Celery_Send_Sms(phone, data) # delay是注册为celery异步任务的关键点
 
  # 5.1 保存code 到 redis中
  redis_client.setex(phone, 60 * 5, code) # phone:code, 5分钟有效期
  # 5.2 从redis中删除这个图片验证码, 以防再次被使用
  redis_client.delete(image_code_uuid)
 
  # 6.存储这个已经发送验证码的手机号,防止频繁发送(使用pipeline 批量操作 )
  pl = redis_client.pipeline()
  pl.setex(phone, 60 * 5, code)
  pl.delete(image_code_uuid)
  pl.execute()
  # 7. 返回结果
  return Response({"code": 200, "msg": "短信发送成功"})

1.启动celery

首先正常启动你的django任务,然后启动celery服务即可。

python manage.py celery worker --loglevel=info

详解Django中异步任务之django-celery

出现上图这个报错不让超级管理员来启动,在settings.py加入以下配置

from celery import Celery, platforms
platforms.C_FORCE_ROOT = True

2.验证celery任务

在搞定上面的东西以后,你就可以通过postman来请求接口让接口使用celery来异步执行任务而不阻塞你的request请求。

详解Django中异步任务之django-celery

到此这篇关于详解Django中异步任务之django-celery的文章就介绍到这了,更多相关Django异步任务内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
python实现socket客户端和服务端简单示例
Feb 24 Python
用python读写excel的方法
Nov 18 Python
Python实现读取目录所有文件的文件名并保存到txt文件代码
Nov 22 Python
Python多线程编程(七):使用Condition实现复杂同步
Apr 05 Python
Python网络爬虫神器PyQuery的基本使用教程
Feb 03 Python
Python处理中文标点符号大集合
May 14 Python
Python 面试中 8 个必考问题
Nov 16 Python
Django2.1.3 中间件使用详解
Nov 26 Python
Python3 SSH远程连接服务器的方法示例
Dec 29 Python
python如何使用socketserver模块实现并发聊天
Dec 14 Python
PyTorch 解决Dataset和Dataloader遇到的问题
Jan 08 Python
OpenCV 表盘指针自动读数的示例代码
Apr 10 Python
Python Django路径配置实现过程解析
Nov 05 #Python
Python基于tkinter canvas实现图片裁剪功能
Nov 05 #Python
Python利用matplotlib绘制散点图的新手教程
Nov 05 #Python
Python如何利用Har文件进行遍历指定字典替换提交的数据详解
Nov 05 #Python
Python word文本自动化操作实现方法解析
Nov 05 #Python
Python自动化办公Excel模块openpyxl原理及用法解析
Nov 05 #Python
Python中用xlwt制作表格实例讲解
Nov 05 #Python
You might like
令PHP初学者头疼十四条问题大总结
2008/11/12 PHP
作为PHP程序员应该了解MongoDB的五件事
2013/06/03 PHP
Thinkphp多文件上传实现方法
2014/10/31 PHP
php获取远程图片并下载保存到本地的方法分析
2016/10/08 PHP
学习YUI.Ext 第六天--关于树TreePanel(Part 2异步获取节点)
2007/03/10 Javascript
javascript之水平横向滚动歌词同步的应用
2007/05/07 Javascript
Extjs4 Treegrid 使用心得分享(经验篇)
2013/07/01 Javascript
jQuery当鼠标悬停时放大图片的效果实例
2013/07/03 Javascript
利用JavaScript阻止表单提交的两种方法
2016/08/11 Javascript
VueJs使用Amaze ui调整列表和内容页面
2017/11/30 Javascript
JS实现利用两个队列表示一个栈的方法
2017/12/13 Javascript
javascript中函数的写法实例代码详解
2018/10/28 Javascript
node-red File读取好保存实例讲解
2019/09/11 Javascript
Vue+Element自定义纵向表格表头教程
2020/10/26 Javascript
[03:03]2014DOTA2国际邀请赛 EG战队专访
2014/07/12 DOTA
python分割和拼接字符串
2013/11/01 Python
python多进程中的内存复制(实例讲解)
2018/01/05 Python
tensorflow 打印内存中的变量方法
2018/07/30 Python
python numpy 常用随机数的产生方法的实现
2019/08/21 Python
如何使用Python多线程测试并发漏洞
2019/12/18 Python
python 实现提取log文件中的关键句子,并进行统计分析
2019/12/24 Python
python模拟预测一下新型冠状病毒肺炎的数据
2020/02/01 Python
html5使用html2canvas实现浏览器截图的示例
2017/08/31 HTML / CSS
澳大利亚头发和美容产品购物网站:OZ Hair & Beauty
2020/03/27 全球购物
护士自我评价
2014/02/01 职场文书
中华美德颂演讲稿
2014/05/20 职场文书
争当四好少年演讲稿
2014/09/13 职场文书
2014年向国旗敬礼活动总结
2014/09/27 职场文书
婚前协议书标准版
2014/10/19 职场文书
党的群众路线教育实践活动个人对照检查材料(公安)
2014/11/05 职场文书
2015年创先争优活动总结
2015/03/27 职场文书
Spring中bean的生命周期之getSingleton方法
2021/06/30 Java/Android
用Python爬取英雄联盟的皮肤详细示例
2021/12/06 Python
面试中老生常谈的MySQL问答集锦夯实基础
2022/03/13 MySQL
Python if else条件语句形式详解
2022/03/24 Python
nginx代理实现静态资源访问的示例代码
2022/07/07 Servers