Celery在Django项目中集成
使用celery第一件要做的最为重要的事情是需要先创建一个Celery实例对象,我们一般叫做celery应用对象,或者更简单直接叫做一个app。app应用对象是我们使用celery所有功能的入口,比如启动celery、创建任务,管理任务,执行任务等.
celery框架有2种使用方式,一种是单独一个项目目录,另一种就是Celery集成到web项目框架中。
Celery作为单个项目运行
项目目录
-- celeryapp
-- sms # 异步任务目录,这里拿发送短信来举例,一个类型的任务就一个目录
- __init__.py
- ronglianyunapi.py # 短信发送文件
- tasks.py # 任务的文件,文件名必须是tasks.py!!!每一个任务就是一个被装饰的函数,写在任务文件中
- __init__.py
- main.py # 入口程序
- settings.py # 配置文件
main.py,代码:
from celery import Celery
# 实例化celery应用,参数一般为项目应用名
app = Celery("lg_shop")
# 通过app实例对象加载配置文件(参数为导包路径)
app.config_from_object("celeryapp.settings")
# 注册任务, 自动搜索并加载任务
# 参数必须必须是一个列表,里面的每一个任务都是任务的路径名称
# app.autodiscover_tasks(["任务1","任务2",....])
app.autodiscover_tasks(["celeryapp.sms"])
# 启动Celery的终端命令
# celery -A celeryapp.main worker --loglevel=info # windows不好使,能接收到任务,但不执行
# celery -A celeryapp.main worker --loglevel=info --pool=solo # windows加上这个参数
# celery -A celeryapp.main worker --loglevel=info -P eventlet -c 10 # 或者使用eventlet,-c是协程的数量,生产环境可以用1000
配置文件settings.py,代码:
REDIS_PASSWORD = "root123456"
REDIS_HOST = "127.0.0.1"
REDIS_PORT = 6379
# 任务队列的链接地址
broker_url = 'redis://:%s@%s:%s/14' % (
REDIS_PASSWORD, REDIS_HOST, REDIS_PORT
)
# 结果队列的链接地址
result_backend = 'redis://:%s@%s:%s/15' % (
REDIS_PASSWORD, REDIS_HOST, REDIS_PORT
)
创建任务文件sms/tasks.py
,任务文件名必须固定为tasks.py
,并创建任务,代码:
from ..main import app
from . import sms_sington
@app.task(name="send_sms_code")
def send_sms_code(tid, mobile, datas):
response = sms_sington.send_sms(tid=tid, mobile=mobile, datas=datas)
return response
@app.task(name="send_sms1")
def send_sms1():
"""没有任何参数的异步任务"""
print('任务:send_sms1执行了...')
@app.task(name="send_sms2")
def send_sms2(mobile, code):
"""有参数的异步任务"""
print(f'任务:send_sms2执行了...mobile={mobile}, code={code}')
@app.task(name="send_sms3")
def send_sms3():
"""有结果的异步任务"""
print('任务:send_sms3执行了...')
return 100
@app.task(name="send_sms4")
def send_sms4(x, y):
"""有结果的异步任务"""
print('任务:send_sms4执行了...')
return x + y
发送短信api,sms/ronglianyunapi.py
import os
import json
from ronglian_sms_sdk import SmsSDK
RONGLIANYUN = {
"accId": '2c94811c86c00e9b0186f2873a040afa',
"accToken": os.environ.get("RONGLIANYUNACCTOKEN"),
"appId": '2c94811c86c00e9b0186f2873b0d0b01',
"reg_tid": 1, # 注册短信验证码的模板ID
"sms_expire": 60, # 短信有效期,单位:秒(s)
"sms_interval": 60, # 短信发送的冷却时间,单位:秒(s)
}
class SMSSington:
def __new__(cls, *args, **kwargs):
if not hasattr(cls, "_instance"):
cls._instance = super().__new__(cls, *args, **kwargs)
ronglianyun = RONGLIANYUN
cls._instance.sms = SmsSDK(ronglianyun.get("accId"), ronglianyun.get("accToken"), ronglianyun.get("appId"))
return cls._instance
def send_sms(self, mobile, datas, tid=1):
"""
发送短信
@params tid: 模板ID,默认测试使用1
@params mobile: 接收短信的手机号,多个手机号使用逗号隔开
单个号码: mobile="13312345678"
多个号码: mobile="13312345678,13312345679,...."
@params datas: 短信模板的参数列表(测试只能发四位验证码)
例如短信模板为: 【云通讯】您的验证码是{1},请于{2}分钟内正确输入。
则datas=("1234",5,)
"""
sdk = self._instance.sms
resp = sdk.sendMessage(tid, mobile, datas)
response = json.loads(resp)
return response
sms/__init__.py
,这个文件的作用是减少tasks.py
里面的导包路径
from .ronglianyunapi import SMSSington
sms_sington = SMSSington()
接下来,我们运行celery。
# 项目根目录下运行
# 启动Celery的终端命令(普通的运行方式)
# celery -A celeryapp.main worker --loglevel=info # windows不好使,能接收到任务,但不执行
# celery -A celeryapp.main worker --loglevel=info --pool=solo # windows加上这个参数
# celery -A celeryapp.main worker --loglevel=info -P eventlet -c 10 # 或者使用eventlet,-c是协程的数量,生产环境可以用1000
# 启动多工作进程,以守护进程的模式运行[一个工作进程就是4个子进程]
# windows大概率报错
# 注意:pidfile和logfile必须以绝对路径来声明
celery multi start worker -A celeryapp.main -l info -n worker1
celery multi start worker -A celeryapp.main -l info -n worker2
# 关闭运行的工作进程
celery multi stop worker -A celeryapp.main -l info -n worker1
celery multi stop worker -A celeryapp.main -l info -n worker2
调用上面的异步任务,拿django的shell进行举例:
# 终端调试
python manage.py shell
# 调用celery执行异步任务
from celeryapp.sms.tasks import send_sms1,send_sms2,send_sms3,send_sms4
mobile = "18533538210"
code = "6666"
# delay 表示马上按顺序来执行异步任务,在celrey的worker工作进程有空闲的就立刻执行
# 可以通过delay异步调用任务,可以没有参数
ret1 = send_sms1.delay()
# 可以通过delay传递异步任务的参数,可以按位置传递参数,也可以使用命名参数
# ret2 = send_sms.delay(mobile=mobile,code=code)
ret2 = send_sms2.delay(mobile,code)
# apply_async 让任务在后面指定时间后执行,时间单位:秒/s
# 任务名.apply_async(args=(参数1,参数2), countdown=定时时间)
ret4 = send_sms4.apply_async(kwargs={"x":10,"y":20},countdown=30)
# 根据返回结果,不管delay,还是apply_async的返回结果都一样的。
ret4.id # 返回一个UUID格式的任务唯一标志符,5b2becb8-c1ba-4e33-8593-9c6fa7ff8c78
ret4.status # 查看当前任务的状态 SUCCESS表示成功! PENDING任务等待
ret4.get() # 获取任务执行的结果[如果任务函数中没有return,则没有结果,如果结果没有出现则会导致阻塞]
if ret4.status == "SUCCESS":
print(ret4.get())
在django的视图里面,我们调用Celery来异步执行任务(这里容联云发送短信举例)。
***/views.py
# 异步发送短信
from celeryapp.sms.tasks import send_sms_code
# 原来的
response = send_sms_code(tid=settings.RONGLIANYUN.get("reg_tid"), mobile=mobile,
datas=(sms_code, SMS_CODE_EXPIRES // 60))
# 改成
response = send_sms_code.delay(tid=settings.RONGLIANYUN.get("reg_tid"), mobile=mobile,
datas=(sms_code, SMS_CODE_EXPIRES // 60))
上面就是使用celery并执行异步任务的第一种方式,适合在一些无法直接集成celery到项目中的场景,或是想celery单独跑在一台服务器上的场景。
Celery作为第三方模块在Django中集成
这里还是拿django来举例,目录结构调整如下:
-- lg_shop/
-- lg_shop/
-- apps/
-- verify/
- tasks.py # 分散在各个子应用下的异步任务模块
-- libs/
-- sms/
- __init__.py
- ronglianyunapi.py
- __init__.py
- __init__.py
- celery_app.py # celery入口程序,相当于上一种用法的main.py
lg_shop/celery_app.py
,主应用目录下创建cerley入口程序,创建celery对象并加载配置和异步任务,代码:
import os
from celery import Celery
# 必须在实例化celery应用对象之前执行(Django项目manage.py里面的)
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'lg_shop.settings.dev')
# 实例化celery应用,参数一般为项目应用名
app = Celery("lg_shop")
# 指定任务的队列名称
app.conf.task_default_queue = 'Celery'
# 可以把配置写在django的项目配置中
# 设置django中配置信息以 "CELERY_"开头为celery的配置信息
app.config_from_object('django.conf:settings', namespace='CELERY')
# 注册任务,自动搜索并加载任务
app.autodiscover_tasks()
# 启动Celery的终端命令
# celery -A lg_shop worker --loglevel=info # windows不好使,能接收到任务,但不执行
# celery -A lg_shop worker --loglevel=info --pool=solo # windows加上这个参数
# celery -A lg_shop worker --loglevel=info -P eventlet -c 10 # 或者使用eventlet,-c是协程的数量,生产环境可以用1000
settings/dev.py,django配置中新增celery相关配置信息,代码:
# celery相关
# Celery异步任务队列框架的配置项[注意:django的配置项必须大写,所以这里的所有配置项必须全部大写]
# 任务队列的链接地址
CELERY_BROKER_URL = 'redis://:%s@%s:%s/14' % (
REDIS_PASSWORD, REDIS_HOST, REDIS_PORT
)
# 结果队列的链接地址
CELERY_RESULT_BACKEND = 'redis://:%s@%s:%s/15' % (
REDIS_PASSWORD, REDIS_HOST, REDIS_PORT
)
# 时区,与django的时区同步
CELERY_TIMEZONE = TIME_ZONE
# 防止死锁
CELERY_FORCE_EXECV = True
# 设置并发的worker数量
CELERYD_CONCURRENCY = 200
# celery的任务结果内容格式
CELERY_ACCEPT_CONTENT = ['json', 'pickle']
# 设置失败允许重试[这个慎用,如果失败任务无法再次执行成功,会产生指数级别的失败记录]
# CELERY_ACKS_LATE = True
# 每个worker工作进程最多执行500个任务被销毁,可以防止内存泄漏,500是举例,根据自己的服务器的性能可以调整数值
# CELERYD_MAX_TASKS_PER_CHILD = 500
# 单个任务的最大运行时间,超时会被杀死[慎用,有大文件操作、长时间上传、下载任务时,需要关闭这个选项,或者设置更长时间]
# CELERYD_TIME_LIMIT = 10 * 60
# 任务发出后,经过一段时间还未收到acknowledge, 就将任务重新交给其他worker执行
CELERY_DISABLE_RATE_LIMITS = True
# 之前定时任务(定时一次调用),使用了apply_async({}, countdown=30);
# 设置定时任务(定时多次调用)的调用列表,需要单独运行SCHEDULE命令才能让celery执行定时任务:
# celery -A celeryapp.main beat,当然worker还是要启动的
# from celery.schedules import crontab
# CELERY_BEAT_SCHEDULE = {
# "send_sms1": { # 定时任务的注册标记符[必须唯一的]
# "task": "send_sms1", # 定时任务的任务名称
# "schedule": 10, # 定时任务的调用时间,10表示每隔10秒调用一次add任务
# # "schedule": crontab(hour=7, minute=30, day_of_week=1), # 定时任务的调用时间,每周一早上7点30分调用一次add任务
# }
# }
lg_shop/__init__.py
,主应用下初始化,代码:
import pymysql
pymysql.install_as_MySQLdb()
from .celery_app import app as celery_app
__all__ = ['celery_app']
***/tasks.py
,这个任务文件要写在子应用下,app.autodiscover_tasks
会自动调用。
from celery import shared_task
from sms import sms_sington
@shared_task(name="send_sms_code")
def send_sms_code(tid, mobile, datas):
response = sms_sington.send_sms(tid=tid, mobile=mobile, datas=datas)
return response
libs/sms/__init__.py
from .ronglianyunapi import SMSSington
sms_sington = SMSSington()
libs/sms/ronglianyunapi.py
import json
from django.conf import settings
from ronglian_sms_sdk import SmsSDK
from logger import log
from response_code import RETCODE
class SMSSington:
def __new__(cls, *args, **kwargs):
if not hasattr(cls, "_instance"):
cls._instance = super().__new__(cls, *args, **kwargs)
ronglianyun = settings.RONGLIANYUN
cls._instance.sms = SmsSDK(ronglianyun.get("accId"), ronglianyun.get("accToken"), ronglianyun.get("appId"))
return cls._instance
def send_sms(self, mobile, datas, tid=1):
"""
发送短信
@params tid: 模板ID,默认测试使用1
@params mobile: 接收短信的手机号,多个手机号使用逗号隔开
单个号码: mobile="13312345678"
多个号码: mobile="13312345678,13312345679,...."
@params datas: 短信模板的参数列表(测试只能发四位验证码)
例如短信模板为: 【云通讯】您的验证码是{1},请于{2}分钟内正确输入。
则datas=("1234",5,)
"""
sdk = self._instance.sms
resp = sdk.sendMessage(tid, mobile, datas)
response = json.loads(resp)
if response.get("statusCode") != "000000":
msg = {"code": RETCODE.SMSCODESENDRR, "msg": f"{mobile}验证码发送失败-{response.get('statusMsg')}"}
log.error(msg)
return response
django中的用户发送短信,就可以改成异步发送短信了。
视图中调用异步发送短信的任务,代码:
# 异步发送短信
from 子应用.tasks import send_sms_code
# 原来的
response = send_sms_code(tid=settings.RONGLIANYUN.get("reg_tid"), mobile=mobile,
datas=(sms_code, SMS_CODE_EXPIRES // 60))
# 改成
response = send_sms_code.delay(tid=settings.RONGLIANYUN.get("reg_tid"), mobile=mobile,
datas=(sms_code, SMS_CODE_EXPIRES // 60))
终端下先启动celery,在django项目根目录下启动。
# 1. 普通运行模式,关闭终端以后,celery就会停止运行
# celery -A 项目名 worker -l info
celery -A lg_shop worker -l info --pool=solo
# 2. 启动多worker进程模式,以守护进程的方式运行,不需要在意终端。但是这种运行模型,一旦停止,需要手动启动。
# windows大概率报错
celery multi start worker -A lg_shop -l info -n lg_shop_worker
# 3. 停止多worker进程模式
celery multi stop worker -A lg_shop -l info -n lg_shop_worker
关于celery中异步任务发布的2个方法的参数如下:
异步任务名.delay(*arg, **kwargs)
异步任务名.apply_async((arg,), {'kwarg': value}, countdown=60, expires=120)
定时任务的调用器启动,可以在运行了worker以后,使用以下命令:
celery -A lg_shop beat
beat调度器关闭了,则定时任务无法执行,如果worker工作进程关闭了,则celery关闭,保存在消息队列中的任务就会囤积在那里。
代码示例
https://github.com/HkwJsxl/lg_shop
Celery在Django项目中集成的更多相关文章
- celery 分布式异步任务框架(celery简单使用、celery多任务结构、celery定时任务、celery计划任务、celery在Django项目中使用Python脚本调用Django环境)
一.celery简介: Celery 是一个强大的 分布式任务队列 的 异步处理框架,它可以让任务的执行完全脱离主程序,甚至可以被分配到其他主机上运行.我们通常使用它来实现异步任务(async tas ...
- celery在Django项目中的使用案例
一.逻辑分析 第一步:在项目根目录新建包 第二步:在使用提交异步任务的位置,导入使用即可 视图函数中使用,导入任务 任务.delay() # 提交任务 第三步:启动worker,如果有定时任务,启动b ...
- Django项目中集成第三方登录时出现的错误
原以为是被反爬 没想到 总结:这里的http应该是https协议,以后要更加小心 了,不能犯这种低级错误
- 分布式队列celery 异步----Django框架中的使用
仅仅是个人学习的过程,发现有问题欢迎留言 一.celery 介绍 celery是一种功能完备的即插即用的任务对列 celery适用异步处理问题,比如上传邮件.上传文件.图像处理等比较耗时的事情 异步执 ...
- iOS原生项目中集成React Native
1.本文的前提条件是,电脑上已经安装了CocoaPods,React Native相关环境. 2.使用Xcode新建一个工程.EmbedRNMeituan [图1] 3.使用CocoaPods安装Re ...
- Java Web学习系列——Maven Web项目中集成使用Spring、MyBatis实现对MySQL的数据访问
本篇内容还是建立在上一篇Java Web学习系列——Maven Web项目中集成使用Spring基础之上,对之前的Maven Web项目进行升级改造,实现对MySQL的数据访问. 添加依赖Jar包 这 ...
- 06_在web项目中集成Spring
在web项目中集成Spring 一.使用Servlet进行集成测试 1.直接在Servlet 加载Spring 配置文件 ApplicationContext applicationContext = ...
- [翻译]在Django项目中添加谷歌统计(Google Analytics)
原文:<Google Analytics tracking code into Django projects, the easy way> 对我来说,制作一个可扩展的Django应用随时 ...
- SpringBoot12 QueryDSL01之QueryDSL介绍、springBoot项目中集成QueryDSL
1 QueryDSL介绍 1.1 背景 QueryDSL的诞生解决了HQL查询类型安全方面的缺陷:HQL查询的扩展需要用字符串拼接的方式进行,这往往会导致代码的阅读困难:通过字符串对域类型和属性的不安 ...
- 如何在你的项目中集成 CAP【手把手视频教程】
前言 之前录制过一期关于CAP的视频,但是由于当时是直播时录制的视频,背景音比较杂所以质量有点差.这次的视频没有直播,直接录制的,视频质量会好很多,第一遍录制完成之后发现播放到一半没有声音,所以又重新 ...
随机推荐
- [转帖]拜托!面试请不要再问我Spring Cloud底层原理
https://www.cnblogs.com/jajian/p/9973555.html 概述# 毫无疑问,Spring Cloud是目前微服务架构领域的翘楚,无数的书籍博客都在讲解这个技术.不过大 ...
- [转帖]JVM NativeMemoryTracking ;jcmd process_id VM.native_memory;Native memory tracking is not enabled
目录 一.Native Memory Tracking (NMT) 是Hotspot VM用来分析VM内部内存使用情况的一个功能.我们可以利用jcmd(jdk自带)这个工具来访问NMT的数据. 1.N ...
- 各开发语言DNS缓存配置建议
作者:翟贺龙 一.背景 在计算机领域,涉及性能优化动作时首先应被考虑的原则之一便是使用缓存,合理的数据缓存机制能够带来以下收益: 1.缩短数据获取路径,热点数据就近缓存以便后续快速读取,从而明显提升处 ...
- 原生js拖拽元素(onmouseup不能够触发的原因)
我们经常会遇见拖拽某一个元素的场景,拖拽也是很常用的: 这次拖拽遇见一个问题,有时在拖拽的时候吗,鼠标松开,元素仍然可以拖拽: 经过查阅资料,发现: 会触发H5原生的拖拽事件.并且不会监听到onmou ...
- Linux命令行从x度网盘下载数据
技术背景 做开源项目的时候,尤其是现在的数据量越来越大,经常会面临到数据往哪里存放的问题.因为自己刚好有一个某度云的会员,看了一下还有几十个TB的空间还没用上.于是考虑把这个网盘变成一个定向共享数据的 ...
- 佳能F-789SGA升级与超频——互联网Tips存档
佳能F-789SGA简介 佳能F-789SGA是一款性价比极高的科学函数计算器,功能与卡西欧fx-991ES近似,稍强于991ES,弱于991CNX. 来自電卓院亜紀良的评价 来自杨高峰的对比总结 来 ...
- 从零开始配置vim(32)——最后再说两句
很抱歉我决定结束这个系列的内容了.原本我打算介绍markdown.orgmode相关的配置,甚至还打算介绍如何在vim 中使用 emacs 的 org-agenda 来进行日常的任务管理.但是出于一些 ...
- Pytorch分布式训练,其他GPU进程占用GPU0的原因
问题 最近跑师兄21年的论文代码,代码里使用了Pytorch分布式训练,在单机8卡的情况下,运行代码,出现如下问题. 也就是说GPU(1..7)上的进程占用了GPU0,这导致GPU0占的显存太多,以至 ...
- 该换Linux版本了!
提起开发,程序员们更青睐于不同版本的Linux操作系统而不是Windows.为什么?因为Linux操作起来更安全.快捷,最重要的是,它的发行版本众多.你可以根据需要挑选最适合的那一款.那么,问题来了, ...
- ECMAScript 2023 新特性预览
ECMAScript 2023 的最终版本预计将于今年 6 月底发布.会议基本已经确定 了 ECMAScript 2023 的新功能列表,预计不会再有任何重大的编辑更改. 着该提案已被 ECMAScr ...