写在前面
通过flask的web接口请求去下发celery定时任务,例如偶尔需要定期后台执行的任务,也可以在配置文件中写死相关的配置任务,例如定期刷新等操作
启动命令
celery -A application.celery worker -l INFO
存储建议
前台手动ctrl+c或者supervisor用信号kill掉celery服务会导致重启服务后任务丢失,原因是用Redis,Celery会把发送的任务临时存储在内存中,如果我们用ctrl+c或者supervisor的kill信号干掉它,那么Celery会无法将内存中的任务信息存储到Redis中.
建议使用RabbitMQ作为消息中间件,这样会实时保存任务信息
常见问题
解决Unable to load celery application.The module bin was not found.
检查celery目录问题,一般pycharm会以项目文件夹为根目录,application.celery需要写为绝对路径
解决not enough values to unpack (expected 3, got 0)问题
--pool=solo 单进程
windows下4.X版本需要指定单进程,目前不支持多进程
linux支持多进程
-P eventlet -c 1000
windows下支持eventlet线程池
Celery指定定时任务
Celery定时任务需要开启轮循,代表注册任务,读取定时任务的执行周期以及配置参数
celery -A bin.celery beat
Celery开启Worker,上面相当于流水线,这里就是工人,流水线开启后,需要开启工人(worker)去执行任务
celery -A application.celery worker -l INFO
目录结构总结
bin-
app-
flask路由文件夹
__init__.py
route.py
setting-
celery配置文件夹
__init__.py
config.py (celery基本配置)
MakeCelery.py (celery初始化类)
tasks-
异步任务目录
__init__.py
tasks.py (flask调用celery异步任务)
__init__.py (重要:初始化flask并读取config.py,通过MakeCelery.py加载celery需要的配置)
celeryWorker.py (celery服务主服务,用于单独加载配置并启动celery服务)
主要代码
routeFunc.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2020/8/24 13:58
# @Author : YanMingHao
# @Site :
# @File : routeFunc.py
# @Software: PyCharm
# @notice : 我写这段代码时,知道我在做什么的,只有老天和我.但是现在,只有老天知道我在做什么.
from bin import app,jsonify,request
from bin.tasks.tasks import add_together
@app.route('/test1/',methods=['POST','GET'])
def TestRequest():
"""
测试请求
:return:
"""
data = request.get_json()
print(data)
num1 = data.get('num1')
num2 = data.get('num2')
print(num1,num2)
add_together.delay(int(num1),int(num2))
return jsonify({'count': '任务下发成功'})
if __name__ == '__main__':
app.debug = True
app.run(host='0.0.0.0',port=8888)
config.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2020/8/15 10:00
# @Author : YanMingHao
# @Site :
# @File : config.py
# @Software: PyCharm
# @notice : 我写这段代码时,知道我在做什么的,只有老天和我.但是现在,只有老天知道我在做什么.
CELERY_BROKER_URL = 'redis://localhost:6379/0'
CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'
CELERY_IMPORTS = "bin.tasks.tasks" # 注册任务
CELERY_TASK_SERIALIZER = "msgpack"
CELERY_RESULT_SERIALIZER = "json"
CELERY_TASK_RESULT_EXPIRES = None
CELERY_ACCEPT_CONTENT = ['json', 'msgpack']
timezone = 'Asia/Shanghai'
enable_utc = True
MakeCelery.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2020/8/15 10:03
# @Author : YanMingHao
# @Site :
# @File : MakeCelery.py
# @Software: PyCharm
# @notice : 我写这段代码时,知道我在做什么的,只有老天和我.但是现在,只有老天知道我在做什么.
from celery import Celery
def makeCelery(app):
"""
* 实例化celery
:param app:
:return:
"""
celery = Celery(
app.import_name,
backend=app.config['CELERY_RESULT_BACKEND'],
broker=app.config['CELERY_BROKER_URL']
)
celery.config_from_object(app.config)
class ContextTask(celery.Task):
def __call__(self, *args, **kwargs):
"""
* 将类变为可调用对象
:param args:
:param kwargs:
:return:
"""
with app.app_context():
"""
打开上下文
"""
return self.run(*args, **kwargs)
celery.Task = ContextTask
return celery
tasks.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2020/8/24 13:58
# @Author : YanMingHao
# @Site :
# @File : tasks.py
# @Software: PyCharm
# @notice : 我写这段代码时,知道我在做什么的,只有老天和我.但是现在,只有老天知道我在做什么.
from bin import celery
import logging
from src.universal.log import record, logFile
@celery.task
def add_together(a, b):
LOGGER = record(filename=logFile('add_together.py'), level=logging.INFO)
count = a + b
LOGGER.info(f"后台任务结果为:{count}")
# return a + b
celeryWorker.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time : 2020/8/15 10:35
# @Author : YanMingHao
# @Site :
# @File : celeryWorker.py
# @Software: PyCharm
# @notice : 我写这段代码时,知道我在做什么的,只有老天和我.但是现在,只有老天知道我在做什么.
from bin import celery
if __name__ == '__main__':
# 什么都不用写,只是为了单独指定这个文件运行celery
pass
(重要)init.py
# -*- coding: utf-8 -*-
# @Time : 2020/8/17 15:13
# @Author : YinBaidong
# @function:
# @motto : Only Me and God know what it's doing!
from flask import Flask,request,jsonify
from bin.setting.MakeCelery import makeCelery
from bin.setting.path import pathFile
from bin.setting import config
app = Flask(__name__) #初始化flask
app.config.from_object(config) # 读取配置文件
celery = makeCelery(app) # 用makeCelery继承flask读取的配置
原文链接:https://blog.csdn.net/yanminghaop/article/details/108258003