# 原创,转载请留言联系
在用django做项目的时候,做到注册模块时,需要发送短信验证码。本来简简单单的做好了,后来优化的时候发现,发送短信验证码的时候需要一点时间,在这个时间之内程序是阻塞的,用户体验太不好了。往往都是点击获取验证码后,过了几秒钟之后才显示发送成功。所以想到了用celery异步任务队列优化一下。
celery原理详解:https://www.cnblogs.com/chichung/p/9957763.html
通过celery可以把发短信验证码的这部分交给其他进程来做,视图继续往下执行,那么当用户点击发送验证码的时候,就能马上显示发送成功了。
还是先看一下大体流程图:
步骤:
1.安装celery
pip install celery
2.创建celery存放文件件
一般来用,celery会独立放在项目文件下。
创建文件夹如下:
celery_tasks/
├── __init__.py
├── main.py # 创建celery应用的地方
└── sms
├── __init__.py
└── tasks.py # 任务函数存放的地方,注意,tasks这个名字是固定的,不能改,如果改的话worker找不到!
3.创建celery应用
在main.py上:
from celery import Celery # 第一个参数,是应用名,可以随便写
# 第二个参数,是中间人broker(用来保存任务)的储存地方,保存在本机的redis的15号库
celery_app = Celery("meiduo",broker="redis://127.0.0.1:6379/15")
4.创建celery任务
@celery.task # 装饰器表示把这个函数标记为celery的任务函数
def send_sms(mobile,sms_codes):
# 下面是实现短信验证码发送的逻辑
result = CCP().send_template_sms(mobile, [sms_codes, constants.SMS_CODE_REDIS_EXPIRES // 60],
constants.SEND_SMS_TEMPLATE_ID)
5.设置django配置文件的路径。
在main.py上:
# 设置django配置文件的路径(需要在创建celery应用之前设置),设置了配置文件,celery才知道django的导包路径是怎么样的!
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "meiduo_mall.settings.dev") # 第一个参数,是应用名,可以随便写
# 第二个参数,是中间人broker(用来保存任务)的储存地方,保存在本机的redis的15号库
celery_app = Celery("meiduo",broker="redis://127.0.0.1:6379/15")
6.指定用celery执行的任务函数的位置
# 设置django配置文件的路径(需要在创建celery应用之前设置),设置了配置文件,celery才知道django的导包路径是怎么样的!
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "meiduo_mall.settings.dev") # 第一个参数,是应用名,可以随便写
# 第二个参数,是中间人broker(用来保存任务)的储存地方,保存在本机的redis的15号库
celery_app = Celery("meiduo",broker="redis://127.0.0.1:6379/15") # 指定任务函数的文件夹位置,表示从哪些位置找到任务函数。
# 查找的方法是,找到sms文件夹,然后就会自动去找tasks.py。这就是为什么task.py不能乱起名的原因。然后找到task.py里面有celery应用装饰的函数。
celery_app.autodiscover_tasks(['celery_tasks.sms'])
7.启动worker进程
celery -A celery应用所在py文件 worker -l info
例: celery -A celery_tasks.main worker -l info服务器启动后能够看到如下任务,worker进程才能正常工作处理任务
[tasks]
. celery_tasks.sms.tasks.send_sms_code
8.通过装饰器name参数自定义任务名(可选)
@celery_app.task(name='send_sms_code')
def send_sms_code(mobile, sms_code):
...
自定义完后,启动celery工作进程在输出信息中可以看到如下任务名
[tasks]
. send_sms_code
9.发送任务: 调用delay方法发送异步任务
在视图可以调用任务函数进行发送任务了,任务会储存在中间人broker,woker空闲时就会取出并执行。
class SmsCodesView(APIView):
def get(self,request,mobile):
...
# 发送验证码
send_sms.delay(mobile,sms_codes) ...
10.worker执行任务
示例:
[2017-01-22 xxxx: INFO/ForkPoolWorker-2] Task
celery_tasks.sms.tasks.send_sms_code[2f4dc753-3cd5-4eaa-994a-d944c45a857c]
succeeded in 3.2456164589966647s: None
拓展
1.中间人broker是怎么存储任务的?
使用json存储:保存了任务函数标识,任务函数名,调用参数等
2.如果任务函数有返回值,应该怎么取?
(1)首先,需要有一个地方存储任务函数的返回值。这里选择redis的14号库。
修改main.py
celery_app = Celery('meiduo',broker='redis://127.0.0.1:6379/15',backend='redis://127.0.0.1:6379/14')
这时候,worker执行完任务函数后,会把任务函数的返回值存储在redis上。
(2)怎么把返回值取出来用呢?
假设发送短信这个任务函数有返回值,如果是0就是发送成功,是-1就是发送失败。
result = send_sms.delay(mobile,sms_codes)
应该怎么拿到result的值呢?
其实,当worker执行完之后,result.ready()的值是True。未执行完是False。
当执行会之后(result.ready=True),可以用get方法取出返回值。
result.get()
(3)怎么把配置文件独立在一个文件里面呢?
1. 在celery_tasks包下创建配置文件 config.py, 并定义配置如下
broker_url ='redis://127.0.0.1:6379/15'
backend_url='redis://127.0.0.1:6379/14'
2. 加载配置文件
celery_app = Celery('meiduo') # 把配置都放到了config.py文件
celery_app.config_from_object('celery_tasks.config')