使用Redis作为任务存储的APScheduler重启后interval类型任务丢失问题
问题产生原因
核心原因:未配置misfire_grace_time参数导致过期interval任务被自动清理
APScheduler默认的任务误点容忍时间misfire_grace_time为0,只要任务的下一次计划执行时间早于服务重启后的当前时间,就会被判定为失效,直接从任务存储中删除。
你的interval任务为每分钟执行一次,服务停机期间必然会错过至少一次执行,重启后APScheduler从Redis加载任务时,会直接将该过期的interval任务移除。而date类型任务的执行时间设置在2120年,远晚于当前时间,不会触发过期清理规则,因此会被正常保留。
其他叠加影响因素
- 代码执行顺序错误:你当前代码先启动调度器,再定义任务执行函数
testfunc。服务重启时,调度器启动后会立刻从Redis加载已存储的任务,此时testfunc还未被定义,任务反序列化时找不到对应的执行函数,会进一步触发任务清理逻辑。 - 同ID任务重复添加无冲突处理:你每次启动脚本都会调用
add_job传入固定ID的任务,默认情况下如果Redis中已存在相同ID的任务,add_job会抛出ConflictingIdError异常,未做异常捕获的情况下可能导致任务添加失败,甚至原有任务被意外覆盖。
修复方案
- 配置任务误点容忍时间,可选择全局配置或单个任务配置:
- 全局配置:在调度器初始化参数中添加
'apscheduler.job_defaults.misfire_grace_time': '300'(单位为秒,示例为允许错过5分钟内的执行) - 单个任务配置:在
add_job时添加参数misfire_grace_time=300
- 全局配置:在调度器初始化参数中添加
- 调整代码执行顺序:先定义任务执行函数,再启动调度器,确保调度器加载任务时能找到对应的执行函数
- 调用
add_job时添加replace_existing=True参数,避免同ID任务添加冲突:
scheduler.add_job(testfunc, 'interval', minutes=1, id='my_job_id', replace_existing=True, misfire_grace_time=300)
内容的提问来源于stack exchange,提问作者TheSaGe
相关产品推荐
相关产品推荐

