Python Flask_APScheduler定时任务的正确(最佳)使用

描述

APScheduler基于Quartz的一个Python定时任务框架,实现了Quartz的所有功能。最近使用Flask框架使用Flask_APScheduler来做定时任务,在使用过程当中也遇到很多问题,例如在定时任务调用的方法中需要用到flask的app.app_context()时,需要使用current_app记录日志时,例如:current_app.logger.info("my_job已执行"),定时任务中使用current_app对象会报错,查看了很多资料,大部分资料都是说没有app就创建一个,这样确实也能解决,但是我总感觉这种解决是有问题的,拿.Net Core来说,使用Quartz.NET定时任务时,定时任务依赖于一个Host(主机)对象,不需要重复创建Host对象,但是Flask的app对象使用过程中却需要重新create app,Quartz.NET也是基于Quartz的定时任务框架,我使用过Quartz.NET,因此始终觉得Flask_APScheduler中create app使用是有问题,终于在过了一段时间后看到一位前辈使用Flask_APScheduler的一篇文章后,瞬间通达了,这个问题终于得到完美解决

最佳使用Flask_APScheduler

安装Flask_APScheduler

bash 复制代码
pip install Flask_APScheduler

1.项目结构图如下:

2.Python 软件包utils下的__init__.py 初始化生成APScheduler对象

这里可以灵活处理,例如:也可以是common软件包下__init__.py里初始化APScheduler

init.py的代码如下:

python 复制代码
import atexit
import platform

from flask_apscheduler import APScheduler

# 初始化生成APScheduler对象
scheduler = APScheduler()


def init_scheduler(app):
    # 解决APScheduler定时任务重复执行的问题
    if platform.system() == 'Linux':
        # Linux 环境下
        fcntl = __import__("fcntl")
        f = open('scheduler.lock', 'wb')
        try:
            fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB)
            scheduler.init_app(app)
            scheduler.start()
        except Exception as e:
            app.logger.error(e)
            print(e)

        def unlock():
            fcntl.flock(f, fcntl.LOCK_UN)
            f.close()

        atexit.register(unlock)
    else:
        # Window 环境下
        msvcrt = __import__('msvcrt')
        f = open('scheduler.lock', 'wb')
        try:
            msvcrt.locking(f.fileno(), msvcrt.LK_NBLCK, 1)
            scheduler.init_app(app)
            scheduler.start()
        except Exception as e:
            pass

        def _unlock_file():
            try:
                f.seek(0)
                msvcrt.locking(f.fileno(), msvcrt.LK_UNLCK, 1)
            except Exception as e:
                pass
        atexit.register(_unlock_file)

3. config.py配置类代码

python 复制代码
class Config:
    JOBS = [
        {
            'id': 'job1',
            'func': 'app:MyService.my_job',  # 注意这里的格式,app 是 Flask 应用对象的名称(app.py),: 后面是任务函数名
            'kwargs': {'job_name': 'job1'},
            'trigger': 'cron',
            'hour': 16,  # 16 点执行
            'minute': 58,  # 58 分执行
            'second': 0  # 0 秒执行
        },
        {
            'id': 'job2',
            'func': 'app:MyService.my_job',  # 注意这里的格式,app 是 Flask 应用对象的名称(app.py),: 后面是任务函数名
            'kwargs': {'job_name': 'job2'},
            'trigger': 'cron',
            'hour': 16,  # 16 点执行
            'minute': 58,  # 58 分执行
            'second': 3  # 3 秒执行
        },
        {
            'id': 'job3',
            'func': 'app:MyService.my_job',  # 注意这里的格式,app 是 Flask 应用对象的名称(app.py),: 后面是任务函数名
            'kwargs': {'job_name': 'job3'},
            'trigger': 'cron',
            'hour': 16,  # 16 点执行
            'minute': 58,  # 58 分执行
            'second': 6  # 6 秒执行
        }
    ]
    # 开启API功能,这样才可以用api的方式去查看和修改定时任务
    SCHEDULER_API_ENABLED = True

4.app.py中代码如下

python 复制代码
from config.config import Config  # 导入Config类的配置
from utils import init_scheduler  # 导入init_scheduler方法
# 创建Flask应用
app = Flask(__name__)
app.config.from_object(Config)  # 读取Config类的配置
init_scheduler(app)  # init_scheduler方法

5. MyService类中的my_job的方法使用app上下文

python 复制代码
from flask import current_app  # 导入flask的current_app(当前app)
from utils import scheduler  # 很关键的一步 导入utils.__init__.py 初始化后的scheduler对象

class MyService:

    @classmethod
    def my_job(cls, job_name):
        # # # 此方法在定时任务多的情况下,会有性能问题,少的情况没啥问题
        # app = create_app()
        # with app.app_context():
        #     current_app.logger.info("my_job已执行")
        # #     print(f"my_job,当前时间{datetime.now()}")
        # # 使用全局APP变量
        # get_app()
        # with APP.app_context():
        #     current_app.logger.info(f"{job_name}已执行")
        #     print(f"my_job,当前时间{datetime.now()}")

        with scheduler.app.app_context():   # 这个sheduler是带有app及其上下文的
            current_app.logger.info(f"{job_name}已执行")

不建议使用 创建一个app的方法

create app的链接:https://blog.csdn.net/weixin_41934979/article/details/140406152

6.执行效果如下:

源代码地址:https://gitee.com/jxzcode_admin/flask-project.git

7.总结

使用的Python 软件包下的__init__.py文件中初始化生成scheduler对象,此对象项目启动后只生成一次,然后导入scheduler对象,在定时任务执行的方法使用: with scheduler.app.app_context(): 就可以 获取flask当前app上下文,不需要create app,个人觉得这才是真正正确使用Flask_APScheduler

参考资料

https://blog.csdn.net/arnolan/article/details/84936075

https://www.jianshu.com/p/d5a46b2d2fd3

相关推荐
喏喏心14 分钟前
深度强化学习:价值迭代与Bellman方程实践
人工智能·python·学习·机器学习
小白勇闯网安圈21 分钟前
supersqli、web2、fileclude、Web_python_template_injection
python·网络安全·web
用户83562907805133 分钟前
从一维到二维:用Spire.XLS轻松将Python列表导出到Excel
后端·python
l木本I1 小时前
uv 技术详解
人工智能·python·深度学习·机器学习·uv
宁大小白1 小时前
pythonstudy Day31
python·机器学习
江上鹤.1482 小时前
Day34模块和库的导入
python
我爱鸢尾花2 小时前
第十四章聚类方法理论及Python实现
大数据·python·机器学习·数据挖掘·数据分析·聚类
言之。2 小时前
Dropbear远程连接
python
dhdjjsjs3 小时前
Day34 PythonStudy
python
一个java开发3 小时前
Dask 配置文件加载机制说明
大数据·python