Flask 与 Celery 异步任务的完美结合:一个轻松有趣的教程
为了防止在长时间不使用工具框架后遗忘其使用方法,以此记录,也希望这些记录对你有所帮助。
安装依赖
首先,咱们得安上咱们的必备工具,非常简单,打开命令行,输入:
pip install Flask Celery redis eventlet
windows10 使用celery必须 安装 eventlet
别担心,这些命令跑起来很快,就像夜店门口的小奶狗一样贴心。
模块化配置
工欲善其事,必先利其器。我们将代码分成几个模块,方便管理和阅读。
celery_config.py
这个模块用来配置 Celery。就像每个故事都需要一个好的开篇,Celery 也需要被好好配置。
# celery_config.py
from celery import Celery
def make_celery(app):
"""
配置 Celery,与 Flask 应用绑定。
:param app: Flask 应用实例
:return: 配置好的 Celery 实例
"""
# 初始化 Celery 的 broker 和 backend
celery = Celery(
app.import_name,
broker=app.config['CELERY_BROKER_URL'],
backend=app.config['CELERY_RESULT_BACKEND']
)
celery.conf.update(app.config) # 更新 Celery 配置
return celery # 返回 Celery 实例
tasks.py
这个模块用来定义我们的任务。就像我们平时爱 procrastinate 而不做的事情一样,但 Celery 可是不会偷懒的。
# tasks.py
from celery_config import make_celery
from flask import Flask
app = Flask(__name__)
# 配置 flask 应用的 broker 和 backend 地址
app.config['CELERY_BROKER_URL'] = 'redis://localhost:6379/0'
app.config['CELERY_RESULT_BACKEND'] = 'redis://localhost:6379/0'
celery = make_celery(app)
@celery.task(bind=True)
def long_task(self):
"""
一个模拟耗时任务的函数。例如:长时间计算、调 API 等。
:param self: Celery 任务实例
:return: 任务完成信息
"""
import time
time.sleep(10) # 模拟长时间的任务
return '任务完成!'
app.py
这是我们的主战场,Flask 应用的大本营。在这里,我们定义 API 路由和服务逻辑。
# app.py
from flask import Flask, request, jsonify
from tasks import long_task
app = Flask(__name__)
@app.route('/start_task', methods=['POST'])
def start_task():
"""
启动一个异步任务。
:return: 返回任务 ID
"""
task = long_task.apply_async() # 异步调用任务
return jsonify({'task_id': task.id}), 202 # 返回任务 ID 和状态码 202
@app.route('/task_status/<task_id>', methods=['GET'])
def task_status(task_id):
"""
查询任务状态。
:param task_id: 任务 ID
:return: 返回任务的当前状态和结果
"""
task = long_task.AsyncResult(task_id) # 获取任务结果
if task.state == 'PENDING':
response = {
'state': task.state,
'status': '等待中...'
}
elif task.state != 'FAILURE':
response = {
'state': task.state,
'result': task.result # 如果任务成功,返回结果
}
if task.state == 'PROGRESS':
response['meta'] = task.info # 任务进行中时的额外信息
else:
response = {
'state': task.state,
'status': str(task.info) # 任务失败,返回错误信息
}
return jsonify(response) # 返回 JSON 格式的响应
if __name__ == '__main__':
app.run(debug=True) # 启动 Flask 应用
配置和运行 Celery
Celery 的配置可是非常灵活的,为了让你的 Celery 跟火箭一样高效,咱们来讲几个常用的配置参数。(非必须)
celery.conf.update(
task_serializer='json',
accept_content=['json'], # 这使得 Celery 只接收 JSON 格式的数据
result_serializer='json',
timezone='UTC',
enable_utc=True,
)
启动 Redis 服务
先确保 Redis 在本地运行。你可以通过以下命令启动 Redis 服务器:
redis-server
启动 Celery Worker
在一个新的终端窗口中启动 Celery worker:
celery -A tasks.celery worker --loglevel=info
让 Celery worker 跑起来,准备接受任务吧!
好的,接下来我们详细讲解一下 .delay()
和 .apply_async()
的区别,以及 Celery 启动命令的参数。
Celery 启动命令参数介绍
启动 Celery worker 可以使用非常多的参数配置,除了基本的 -A
和 --loglevel
,我们来讲解一下 -P
和其他一些重要参数:
celery -A celery_app.celery worker -P eventlet --loglevel=info
-
-A celery_app.celery
: 这里的-A
表示指定 Celery 应用实例,celery_app.celery
的意思是我们在celery_app.py
文件中定义了celery
实例。(根据自己的文件名来) -
-P eventlet
: 这里的-P
是指工作模式(Pool),eventlet
是一种协程库(类似于gevent
),适用于需要处理大量 I/O 操作的任务。默认的 Pool 是prefork
,适用于 CPU 密集型任务。prefork
: 默认进程池模式。适合 CPU 密集型任务。solo
: 单进程模式。适合调试和开发。eventlet
: 使用 Eventlet 协程。适合 I/O 密集型任务。gevent
: 使用 Gevent 协程。适合 I/O 密集型任务。
-
--loglevel=info
: 这里是设置日志级别,常见的日志级别包括DEBUG
、INFO
、WARNING
、ERROR
、CRITICAL
。在生产环境中,一般设置成INFO
或更高级别。
其他一些有用的 Celery 参数
-
--concurrency
: 设置任务并发的 worker 数量。默认情况下,Celery 会自动设置为可用 CPU 的数量。celery -A celery_app.celery worker --concurrency=4
-
--time-limit
和--soft-time-limit
: 设置任务执行的时间限制(硬/软时间限制)。软时间限制会给任务一个即时的取消信号,而硬时间限制会强制终止任务。celery -A celery_app.celery worker --time-limit=300 --soft-time-limit=200
-
-Q
或--queues
: 指定 worker 监听的队列。这样可以将某些任务发送到特定的队列,从而仅让某些 worker 处理这些任务。celery -A celery_app.celery worker -Q high_priority,low_priority
-
-n
或--hostname
: 设置 worker 的 hostname。这在部署多个 worker 时很有用,可以对它们进行区分。celery -A celery_app.celery worker -n worker1@%h
启动 Flask 应用
最后,在另一个终端中启动 Flask 应用:
python app.py
测试 API
-
启动一个任务:
curl -X POST http://127.0.0.1:5000/start_task
你会收到一个任务 ID,像这样:
{"task_id": "some_task_id"}
-
查询任务状态:
curl http://127.0.0.1:5000/task_status/some_task_id
瞧,这就是一个完整的流程!你现在可以优雅地处理那些耗时任务,伴随着红茶和 Python 的清香,在一切运转良好的情况下,恭喜你,你已经成功集成了 Flask 与 Celery!
如果你觉得这有意思,记得给自己点个赞!继续探索,继续编程,加油!👨💻👩💻🚀