金天牛

导航

定时任务和fastapi的结合来解决定时任务被关闭的问题

前言:

      最早以前使用apscheduler,写了些定时脚本,放在服务器上运行。可服务器是共用的,偶尔会被关闭,导致定时任务不在了,而过了多天才发现。如此反复几次,决定解决这个问题。

方法:

      经研究,使用fastapi和apscheduler结合,利用gunicorn作为 WSGI HTTP 服务,这样部署了一个web服务。再配置 gunicorn.service服务开机自启,利用fastapi动态加载的特性,完美的解决了服务器重启定时任务消失的问题,还顺带增加了自动更新定时脚本的功能,一个字:爽。

过程如下:

     1.增加tasks文件

  此文件主要是写定时任务。导入其他需要执行的类或者函数,在这个里面统一管理任务。内容举例:

  

 1 job_defaults = {'max_instances': 50}   # 设置默认的任务实例数量
 2 scheduler = BackgroundScheduler(job_defaults=job_defaults)   # 实例化调度器
 3 
 4 
 5 @scheduler.scheduled_job('cron', hour=18, minute=45, second=0)   # 每天18点45执行
 6 def first_job():
 7     holo_act_time()
 8     logging.info("每天18点45的任务执行完毕")
 9 
10 
11 @scheduler.scheduled_job('interval', minutes=30)   #每30分钟执行一次
12 def interval_third_job():13     interface_check()
14 logging.info("每30分钟的任务执行完毕")

 

      2.增加fastapi框架,例如命名为start.py

 1 from fastapi import FastAPI,Query
 2 import logging
 3 import uvicorn
 4 from contextlib import asynccontextmanager
 5 from tasks import scheduler
 6 
 7 
 8 @asynccontextmanager
 9 async def lifespan(app: FastAPI):    # 定义一个上下文管理器,用于启动和关闭时执行一些操作
10     scheduler.start()
11     logging.info("定时任务启动")
12     yield
13     scheduler.shutdown()
14     logging.info("定时任务 Shutting down")
15 
16 
17 app = FastAPI(lifespan=lifespan)     # 通过lifespan参数,实现在启动和关闭时执行一些操作
18 
19 @app.get("/health/")
20 async def health():          # 健康检查接口
21     return {"status": "success"}
22 
23 if __name__ == "__main__":
24     uvicorn.run(app='start:app', host="127.0.0.1", port=8080, reload=True)   #app='start:app'中,start与此文件的名称相同

 

      3.增加gunicorn.py

      

 1 import os
 2 
 3 # 设置守护进程
 4 daemon=True
 5 # 监听内网端口8000
 6 bind='0.0.0.0:808sudo 0'
 7 # 设置进程文件目录
 8 pidfile='./gunicorn.pid'
 9 chdir='./' # 工作目录
10 # 工作模式
11 worker_class='uvicorn.workers.UvicornWorker'
12 # 并行工作进程数 核心数*2+1个
13 workers=1  #multiprocessing.cpu_count()+1
14 # 指定每个工作者的线程数
15 threads=4
16 # 设置最大并发量
17 worker_connections = 2000
18 loglevel='debug' # 错误日志的日志级别
19 access_log_format = '%(t)s %(p)s %(h)s "%(r)s" %(s)s %(L)s %(b)s %(f)s" "%(a)s"'
20 # 设置访问日志和错误信息日志路径
21 log_dir = "./logs"
22 if not os.path.exists(log_dir):
23     os.makedirs(log_dir)
24 accesslog = "./logs/gunicorn_access.log"
25 errorlog = "./logs/gunicorn_error.log"

   在Linux环境下,就可以使用命令启动了:gunicorn start:app -c gunicorn.py

碰到的问题:

      1.定时任务的服务被其他用户关闭。

      使用另一个定时任务去检查fastapi的一个接口,保障接口是通的,当接口访问失败时发送通知给用户。

      这个定时任务建议使用linux的crontab来调度,只要服务器正常,这个任务就能正常执行。

      2.定时任务执行失败:

      配置了一个定时任务,每天8点执行。结果回头检查时发现执行失败,报错Run time of job ... was missed by ...

     经分析,是这个定时任务错误了执行条件。于是在定时任务中增加misfire_grace_time参数,问题解决。

      装饰器举例:

      @scheduler.scheduled_job('cron', hour=7, minute=10, misfire_grace_time=None)

posted on 2024-04-24 14:36  金天牛  阅读(302)  评论(0编辑  收藏  举报