Flask中使用Celery教程
不管是使用什么编程语言,使用什么框架。在服务器上执行耗时操作,比如网络请求、视频转码、图片处理等。如果想实现快速响应客户端的需求,则必须使用任务队列。任务队列是一个单独的程序,和网站没有直接关系,任务队列提供了接口,能在网站中通过代码操作任务队列,比如:添加任务,查看任务结果等。今天我们来说一下在Flask中使用Celery的正确姿势。
一、Celery介绍:
Celery 是一个简单、灵活、可靠的分布式系统,用于处理大量消息,同时提供维护此类系统所需的工具。它是一个专注于实时处理的任务队列,同时也支持任务调度。关于更详细的Celery的介绍,可以查看Celery的官方文档:https://docs.celeryproject.org/en/stable/getting-started/introduction.html。
通过以下命令即可安装Celery:
pip install celery
我们项目使用Python开发,因此通过pip安装。如果读者使用Node.js,可以使用node-celery-ts,如果是用PHP,则可以使用celery-php。
二、Broker和Backend:
要理解Broker和Backend,首先来说一下Celery的工作原理。来看下这幅图:
Celery支持手动发布任务,也支持定时任务。不管任务从哪里来,会先把任务存放到Broker(中间人)中,常用作Celery Broker的有Redis、RabbitMQ、数据库等,其中Redis和RabbitMQ的稳定性和效率是最高的。接着Celery会生成worker,来从Broker中读取任务执行。执行完成后,再把执行后的结果存放到Backend中,常用作Celery Backend的有Redis和数据库。
Celery官方推荐的Broker和Backend搭配为:RabbitMQ(Baoker)+Redis(Backend)。我们平常一台服务器上运行Redis和RabbitMQ有点太浪费了,而且RabbitMQ只有在消息非常大的时候才能体现优势,因此一般我们直接使用Redis作为Broker和Backend即可。
三、Redis安装和使用:
Redis官方是只有Linux版本的,关于Redis在Linux的安装,读者可以直接看官方文档:https://redis.io/download,或者使用带有Redis的Docker即可。Windows安装Redis教程也有些地方需要注意,因此我单独写了一份文档,读者可以参考这里:在Windows上安装Redis超详细文档。
四、Flask中使用Celery:
Celery和Redis都安装成功后,就可以在Flask中集成Celery了。当然Flask官方文档也描述了如何集成Celery,但是那种方式不适合现实中大型项目结构的,很容易引起循环引用的问题。这里我的源码结构如下:
|- project
|-- apps
|--- auth
|---- views.py
| -- app.py
| -- mycelery.py
其中和celery有关系的文件如下:
- mycelery.py:创建celery对象,并且添加了任务。
- app.py:对celery进行app绑定。
- views.py:调用celery中的任务。
就以发送邮件为例,我的这三个文件的代码如下:
mycelery.py:
from flask_mail import Message
from exts import mail
from celery import Celery
# 定义任务函数
def send_mail(recipient,subject,body):
message = Message(subject=subject,recipients=[recipient],body=body)
mail.send(message)
return {"status": "SUCCESS"}
# 创建celery对象
def make_celery(app):
celery = Celery(app.import_name, backend=app.config['CELERY_RESULT_BACKEND'],
broker=app.config['CELERY_BROKER_URL'])
TaskBase = celery.Task
class ContextTask(TaskBase):
abstract = True
def __call__(self, *args, **kwargs):
with app.app_context():
return TaskBase.__call__(self, *args, **kwargs)
celery.Task = ContextTask
app.celery = celery
# 添加任务
celery.task(name="send_mail")(send_mail)
return celery
app.py:
from mycelery import make_celery
# 构建celery
celery = make_celery(app)
views.py:
from flask import current_app, jsonify
@bp.route("/mail")
def mail_test():
try:
email = request.args.get("mail")
subject="邮箱主题"
body = "邮箱内容"
current_app.celery.send_task("send_mail",(email,subject,body))
return jsonify("success")
except Exception as e:
print(e)
return jsonify("fail")
五、运行Celery:
打开cmd终端,然后输入以下命令即可运行Celery:
celery -A app.celery worker --loglevel=info -P gevent
其中的celery -A是固定写法,app代表我的app.py模块,celery代表我的app.py中的celery对象,--loglevel代表日志级别,如果在windows上,还需要使用-P gevent参数,并且需要通过pip安装gevent库。以上即成功运行了Celery,我们访问发送邮件的URL(/mail),即可成功使用celery异步发送邮件了。
六、访问任务结果:
在实际业务场景中,经常需要查看某个任务的执行状态。比如视频转码,我们会在客户端查看是否转码成功。这时候可以定义一个查看任务状态的URL,将任务状态返回。比如:
@app.route('/status/<task_id>')
def taskstatus(task_id):
task = long_task.AsyncResult(task_id)
if task.state == 'PENDING':
# 任务还没开始
response = {
'state': task.state,
'status': '排队中...'
}
elif task.state != 'FAILURE':
response = {
'state': task.state,
'status': task.info.get('status', '')
}
if 'result' in task.info:
response['result'] = task.info['result']
else:
# 如果不是PENDING,或者SUCCESS,那么可能是出现异常了
response = {
'state': task.state,
'status': str(task.info), # 返回错误信息
}
return jsonify(response)
以上便是Flask中使用Celery的全部内容,可以说比较详细的,都是干货输出,希望对你有帮助。