解决方案:APScheduler定时任务不执行,报错Run time of job ... was missed by ...

简介: 解决方案:APScheduler定时任务不执行,报错Run time of job ... was missed by ...


ApScheduler

APScheduler(Advanced Python Scheduler)是一个用于在 Python 应用程序中执行定时任务的库。它提供了一种简单而强大的方式,允许你在指定的时间间隔、日期或特定事件触发时执行任务。

问题背景

最近公司项目中遇到了个 ApScheduler 不执行的奇葩问题,这个项目有两个环境,一个是外网的开发环境,一个是部署到客户现场的内网环境,最近现场反馈好几个定时任务最近到时间都不会执行,而且很随机,有时候就会执行,有时候又不会执行,和抽风了一样。

解决方案

最后定位到是由于现场创建的定时任务太多了(八十多个),APScheduler 默认的调度配置忙不过来了。

最开始的代码写的比较简单,都是基于默认的配置:

...
jobstores = {
    'default': SQLAlchemyJobStore(url='sqlite:///jobs.sqlite')
}
back_scheduler = BackgroundScheduler(timezone="Asia/Shanghai", jobstores=jobstores)
...

翻阅官方文档可以看到,BackgroundScheduler 默认的执行器是 10 个容量的线程执行器。注意这个 10!从下面的文档可以看到。

APScheduler Documentation - Configuring the scheduler

定时任务没有执行可能有两个原因:

  1. 定时任务要执行的时间正好发生了停机/重启。这种情况可能性比较小,除非你真的运气不好,恰好赶在了那个时间。
  2. **Executor 如果是默认的 10 个容量的线程池,恰好 10 个线程都在忙,恰好又有一个任务该执行了,由于没有空闲线程来处理,这个任务将被抛弃。**这个问题就比较常见了,也是我遇到问题的罪魁祸首。如果是因为没有线程处理导致的定时任务不执行,那么会输出日志:Run time of job "xxx (trigger: cron[year='*', month='*', day='*', day_of_week='*', hour='*', minute='*', second='*'], next run at: 2024-01-05 11:17:37 CST)" was missed by 0:00:05.255671,抓住关键词:was missed by,那么基本上就是这个问题了。

这两个原因都可以从官网中找到:

APScheduler Documentation - Missed job executions and coalescing

最后修改代码,适当加大线程池大小,并在创建任务的时候加上 misfire_grace_time 参数。

...
jobstores = {
    'default': SQLAlchemyJobStore(url='sqlite:///jobs.sqlite')
}
job_defaults = {
    'coalesce': True,
    'misfire_grace_time': None
}
# 加大线程池大小
executors = {
    'default': ThreadPoolExecutor(30)
}
back_scheduler = BackgroundScheduler(timezone="Asia/Shanghai", jobstores=jobstores, job_defaults=job_defaults, executors=executors)
...

也可以在创建任务的时候为每个任务单独指定:

...
# 当任务被唤起时,如果在 misfire_grace_time 时间差内,依然运行。
back_scheduler.add_job(... , misfire_grace_time=30)
...

每个任务都有一个 misfire_grace_time,单位:秒,默认是 0 秒。意思是那些错过的任务在有条件执行时(有线程空闲出来/服务已恢复),如果还没有超过 misfire_grace_time,就会被再次执行。如果 misfire_grace_time=None,就是不论任务错过了多长时间,都会再次执行。



相关文章
|
4月前
|
资源调度 Java
在SchedulerX中,你可以使用`schedulerx.submitTask(taskName)`方法来提交并执行单个任务
【1月更文挑战第7天】【1月更文挑战第34篇】在SchedulerX中,你可以使用`schedulerx.submitTask(taskName)`方法来提交并执行单个任务
22 1
|
Java Spring
@Scheduled 多个定时任务同时执行
这篇文章主要介绍了springBoot @Scheduled实现多个任务同时开始执行,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
744 0
|
4月前
|
资源调度
在SchedulerX中,你可以使用`schedulerx.output()`函数来向Worker报告运行结果
【1月更文挑战第7天】【1月更文挑战第35篇】在SchedulerX中,你可以使用`schedulerx.output()`函数来向Worker报告运行结果
20 1
|
Java 调度
定时任务@Scheduled 和 异步@Async
定时任务@Scheduled 和 异步@Async
|
调度
解决使用@Scheduled创建任务时无法在同一时间执行多个任务的BUG
解决使用@Scheduled创建任务时无法在同一时间执行多个任务的BUG
128 0
|
存储 NoSQL 关系型数据库
|
存储 Java Linux
Python----使用apscheduler模块设置定时任务
Python----使用apscheduler模块设置定时任务
1083 0
定时测试BlockingScheduler
定时测试BlockingScheduler
182 0