APScheduler任务不执行主因是jobstore选错:默认MemoryJobStore内存型,进程退出即丢失;需改用SQLAlchemyJobStore(如SQLite)实现持久化,且不可混用多jobstore。

APScheduler 的 jobstore 选错会导致任务不执行
很多人写完 add_job() 就以为万事大吉,结果脚本跑一次就停,定时任务根本没触发。核心问题常出在 jobstore 配置上:默认的 MemoryJobStore 是内存型,进程一退出所有任务就丢了,根本没法“定时”。要持久化调度,必须显式指定数据库后端。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 用 SQLite 最轻量:
SQLAlchemyJobStore(url='sqlite:///jobs.sqlite'),首次运行会自动建表 - 如果已用 PostgreSQL/MySQL,直接复用连接串,但注意表名前缀别冲突(可通过
tablename参数指定) - 别把
MemoryJobStore和SQLAlchemyJobStore混在同一个Scheduler实例里——APScheduler 不支持多 jobstore 共存于单实例(除非用BackgroundScheduler+ 自定义封装)
爬虫函数里不能直接 print 或写文件,得加异常兜底和日志
定时任务在后台跑,print() 不会输出到终端,写相对路径文件可能因工作目录变化而失败(比如 systemd 启动时工作目录是 /)。更严重的是,一次请求失败若没捕获,整个 job 会中断,后续调度照常但实际没干活。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 用
logging替代print(),初始化时指定文件路径:logging.basicConfig(filename='/var/log/my_spider.log', level=logging.INFO) - 爬虫主逻辑必须包在
try...except Exception as e:里,记录错误并return,避免阻塞调度器线程 - 写文件一律用绝对路径,或启动前用
os.chdir('/path/to/project')固定工作目录 - 对 requests 调用必须设
timeout=(3, 7),防止卡死导致下一轮调度被跳过
使用 BlockingScheduler 还是 BackgroundScheduler?看部署场景
本地测试用 BlockingScheduler 最简单,但一旦部署到服务器,它会独占主线程,没法再接 Ctrl+C、没法响应信号、更没法和 Flask/FastAPI 共存。生产环境几乎都该用 BackgroundScheduler。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 开发调试阶段可用
BlockingScheduler,配合max_instances=1防止并发抓取同一页面 - 部署到 Linux 服务(systemd)或 Docker 时,必须换
BackgroundScheduler,且要在启动后显式调用.start() -
BackgroundScheduler启动后,主程序不能立即退出,得加个while True: time.sleep(3600)或监听信号保持存活 - 若脚本还要提供 Web 接口(如加个 /status 查当前任务),只能选
BackgroundScheduler,否则线程冲突
job 触发时间不准?检查 trigger 类型和 misfire_grace_time
用 CronTrigger(hour='*/2') 本意是每两小时跑一次,结果发现有时延迟 5 分钟甚至更久。这不是 APScheduler bug,而是默认容忍 1 分钟的“失火”(misfire)——如果上次任务还没结束,新任务就被丢弃了。
实操建议:
立即学习“Python免费学习笔记(深入)”;
- 对耗时稳定的爬虫,设
misfire_grace_time=30(秒),超过 30 秒没执行就直接丢弃,避免堆积 - 想严格按时触发(哪怕上一轮还在跑),加参数
coalesce=True,把错过的多次触发合并成一次 - 避免用
IntervalTrigger(minutes=90)这种非整点间隔,系统负载高时容易漂移;优先用CronTrigger(minute='0', hour='*/3')对齐系统时钟 - Linux 上确保系统时区正确:
timedatectl status,Python 里别依赖datetime.now()做判断,统一用datetime.utcnow().replace(tzinfo=timezone.utc)
SQLAlchemyJobStore,或者忘了 try/except,脚本上线后就变成“看似在跑,其实啥也没干”。


















