Flask-ApScheduler 任务未执行问题
Flask-ApScheduler 任务未执行问题
在开发时,使用flask run启动 flask 时,ApScheduler 定时任务没有按计划执行原因分析。
ApScheduler 任务配置
Config = { SCHEDULER_JOBS = [ { 'id': 'ims_info', # 任务标识 'func': 'task_1:main', # 运行函数 'trigger': 'interval', # 定时任务的类型 'seconds': 900 # 运行的间隔时间 } ] SCHEDULER_API_ENABLED = True SCHEDULER_TIMEZONE = 'Asia/Shanghai' SCHEDULER_LOCK_FILE = 'scheduler.lock' }
ApScheduler 初始化
为了防止使用 gunicorn 启动 flask 时,重复启动任务,在创建 Apscheduler 对象时增加文件锁
import fcntl import atexit import flask from flask import Flask, request, g, make_response from flask_apscheduler import APScheduler from apscheduler.schedulers.background import BackgroundScheduler def create_apscheduler(flask_app): """创建 Apscheduler 对象,使用文件锁防止用 gunicorn 启动 flask 时,重复启动多个任务""" f = open(Config.SCHEDULER_LOCK_FILE, 'wb') try: fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB) scheduler = APScheduler(BackgroundScheduler()) # 创建 Apscheduler 对象 scheduler.init_app(flask_app) scheduler.start() # 启动任务列表 except Exception as _: pass def unlock(): fcntl.flock(f, fcntl.LOCK_UN) f.close() atexit.register(unlock) app = Flask(__name__) app.config.from_object(Config) create_apscheduler(app)
问题原因
flask 使用 debug 模式启动时,会创建一个子进程,Flask-ApScheduler 为了防止启动两次任务,只在子进程中启动任务。
# Flask-ApScheduler 启动源码 def start(self, paused=False): """ Start the scheduler. :param bool paused: if True, don't start job processing until resume is called. """ # Flask in debug mode spawns a child process so that it can restart the process each time your code changes, # the new child process initializes and starts a new APScheduler causing the jobs to run twice. if flask.helpers.get_debug_flag() and not werkzeug.serving.is_running_from_reloader(): return if self.host_name not in self.allowed_hosts and '*' not in self.allowed_hosts: LOGGER.debug('Host name %s is not allowed to start the APScheduler. Servers allowed: %s' % (self.host_name, ','.join(self.allowed_hosts))) return self._scheduler.start(paused=paused)
这与前面防止 gunicorn 启动多次任务的文件锁机制冲突,最后导致任务一次也没有启动:
- 文件锁保证只在第一个进程中执行 Flask-ApScheduler 初始化及启动,也就是 debug 时的主进程;
- Flask-ApScheduler 的 start 方法中只会在子进程启动时启动任务;
问题解决
在文件锁前增加 debug 模式判断,当 debug 模式时,不使用文件锁:
def create_apscheduler(flask_app): """创建 Apscheduler 对象,使用文件锁防止用 gunicorn 启动 flask 时,重复启动多个任务""" if flask.helpers.get_debug_flag(): scheduler = APScheduler(BackgroundScheduler()) # 创建 Apscheduler 对象 scheduler.init_app(flask_app) scheduler.start() # 启动任务列表 else: f = open(Config.SCHEDULER_LOCK_FILE, 'wb') try: fcntl.flock(f, fcntl.LOCK_EX | fcntl.LOCK_NB) scheduler = APScheduler(BackgroundScheduler()) # 创建 Apscheduler 对象 scheduler.init_app(flask_app) scheduler.start() # 启动任务列表 except Exception as _: pass def unlock(): fcntl.flock(f, fcntl.LOCK_UN) f.close() atexit.register(unlock)
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步