Flask+Celery实现动态添加定时任务

文章目录

      • 写在前面
      • 启动命令
      • 存储建议
      • 常见问题
          • 解决Unable to load celery application.The module bin was not found.
          • 解决not enough values to unpack (expected 3, got 0)问题
      • Celery指定定时任务
          • 目录结构总结
      • 主要代码
            • routeFunc.py
            • config.py
            • MakeCelery.py
            • tasks.py
            • celeryWorker.py
            • (重要)__init__.py

写在前面

通过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读取的配置

你可能感兴趣的:(celery,flask,python)