大家好哦,最近做项目的时候,需要用到celery,这篇文章就讲一讲在flask中怎么使用celery和redis。
在开始之前,先来了解一下celery都可以做些什么。
首先,它是做异步任务,例如发送邮件,短信,还可以做定时任务,还有如果接口运行时间过长的话,在不影响结果的情况下,可以先将结果返回,在用celery做异步处理。
接下来,了解一下celery的核心模块
Task:就是任务,有异步任务和定时任务
Broker:中间人,接收生产者发来的消息即Task,将任务存入队列。任务的消费者是Worker。Celery本身不提供队列服务,推荐用Redis或RabbitMQ实现队列服务。
Worker:执行任务的单元,它实时监控消息队列,如果有任务就获取任务并执行它。
Beat:定时任务调度器,根据配置定时将任务发送给Broker。
Backend:用于存储任务的执行结果
了解之后,咱们开始正文
首先安装依赖celery和redis
pip install celery
pip install redis
安装redis服务
下载路径为 https://github.com/MSOpenTech/redis/releases
此刻验证一下,是否安装成功,redis-cli
安装成功之后,接下来要写代码了
代码目录结构 :
celery_tasks模块主要是celery的一些配置,直接上代码
celery.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from celery import Celery
celery_app = Celery('tasks')
celery_app.config_from_object('celery_tasks.celeryconfig')
celeryconfig.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from datetime import timedelta
# celery配置
# 消息代理
BROKER_URL = 'redis://127.0.0.1:6379/0'
# 存储任务执行结果
CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/1'
# 任务的序列化方式
CELERY_TASK_SERIALIZER = 'json'
# 任务执行结果的序列化方式
CELERY_RESULT_SERIALIZER = 'json'
# 任务过期时间
CELERY_TASK_RESULT_EXPIRES = 60 * 60 * 24
# 接受内容类型
CELERY_ACCEPT_CONTENT = ['json']
# 超时再分配时间
BROKER_TRANSPORT_OPTIONS = {'visibility_timeout': 3600}
# 每个worker执行了多少任务就会死掉,避免内存泄露
CELERYD_MAX_TASKS_PER_CHILD = 500
# 时区设置,用于定时任务
CELERY_TIMEZONE = 'Asia/Shanghai'
CELERY_ENABLE_UTC = False
# 任务导入,包括异步任务和定时任务
CELERY_IMPORTS = (
'run_server',
)
# 计划任务
CELERYBEAT_SCHEDULE = {
'test_reminders': {
# task就是需要执行计划任务的函数
'task': 'run_server.test',
# 配置计划任务的执行时间,这里是每60秒执行一次
'schedule': timedelta(seconds=60),
# 传入给计划任务函数的参数
'args': None
},
}
redis的配置
#!/usr/bin/env python
import time
import redis
from redis.exceptions import ConnectionError as RedisConnectionError
class VodRedis(redis.Redis):
reconnect_timer = 10 # second
connection_down_timestamp = 0
def execute_command(self, *args, **options):
try:
ok_time = time.time() - (self.connection_down_timestamp + self.reconnect_timer)
if ok_time > 0:
self.connection_down_timestamp = 0
return super(VodRedis, self).execute_command(*args, **options)
return None
except RedisConnectionError:
self.connection_down_timestamp = time.time()
return None
def redis_pool(db):
return redis.ConnectionPool(host='127.0.0.1', port='6379', db=db, socket_timeout=5)
default_pool = redis_pool(0)
redis_session = VodRedis(connection_pool=default_pool)
def create_redis_session():
return redis_session
run_server.py
#coding:utf-8
#run_server.py
import time
from flask import Flask, request, render_template
from werkzeug.utils import secure_filename
from celery_tasks.celery import celery_app
from celery.app.control import Control
#服务命名为app
from redis_tasks.redis_util import redis_session
app = Flask(__name__)
@app.route('/upload', endpoint='upload')
#此处需加endpoint,否则报错
def upload_file():
return render_template('upload.html')
@app.route('/uploader', endpoint='uploader',methods=['GET', 'POST'])
def upload_file():
if request.method == 'POST':
f = request.files['file']
f.save(secure_filename(f.filename))
for i in range(10):
test.delay()
return 'file uploaded successfully'
@celery_app.task(name='run_server.test')
def test():
print('开始')
time.sleep(10000)
time.sleep(10000)
print('777777')
print('hahahha')
@app.route('/del_tasks', methods=['GET'])
def upload_file():
if request.method == 'GET':
task_id = request.args.get('task_id')
# 删除redis中的key
all_key = redis_session.keys('celery')
if all_key:
redis_session.ltrim('celery', 1, 0)
# 删除celery正在执行的任务
celery_control = Control(app=celery_app)
celery_control.revoke(task_id, terminate=True)
return '请求成功'
else:
return '请求方式不对'
if __name__ == '__main__':
app.run()
接下来咱们要启动celery
celery -A celery_works.celery worker
此时可能会报错
ValueError: not enough values to unpack (expected 3, got 0)
解决方法
pip install eventlet
运行命令:celery -A celery_works.celery worker -P eventlet
接下来运行项目成功后,请求接口/uploader,可以查看到redis中的任务和celery正在执行的任务,如果想要清空缓存或者是删除celery,调用接口/del_tasks