FastAPI定时任务APScheduler集成
一、前言
APScheduler
定时任务传送门
二、在FastAPI中集成aAPScheduler
- 使用FastAPI启动前后处理程序进行启动任务
2.1 定时任务配置
- 使用
AsyncIOScheduler
调度器 - 使用
Redis
存储器 - 使用
ThreadPoolExecutor
执行器
from datetime import datetime
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.jobstores.redis import RedisJobStore
from apscheduler.executors.pool import ThreadPoolExecutor
REDIS_DB = {
"db": 1,
"host": "127.0.0.1"
}
def func(name):
now = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print(now + f" Hello world, {name}")
interval_task = {
# 配置存储器
"jobstores": {
# 使用Redis进行存储
'default': RedisJobStore(**REDIS_DB)
},
# 配置执行器
"executors": {
# 使用进程池进行调度,最大进程数是10个
'default': ProcessPoolExecutor(10)
},
# 创建job时的默认参数
"job_defaults": {
'coalesce': False, # 是否合并执行
'max_instances': 3, # 最大实例数
}
}
scheduler = AsyncIOScheduler(**interval_task)
# 添加一个定时任务
scheduler.add_job(func, 'interval', seconds=3, args=["desire"], id="desire_job", replace_existing=True)
2.2 启动FastAPI之前启动定时任务
from fastapi import FastAPI
# 导入定时任务配置
from scheduler import scheduler
app = FastAPI()
@app.on_event("startup")
async def start_event():
scheduler.start()
print("定时任务启动成功")
@app.get("/list")
async def jobs():
jobs = scheduler.get_jobs()
return [job.id for job in jobs]
2.3 挂载到app上
1)创建注册定时器的方法
def register_scheduler(app: FastAPI):
@app.on_event("startup")
async def start_event():
scheduler.start()
print("定时任务启动成功")
2)挂载到app上
from fastapi import FastAPI
app = FastAPI()
# 进行挂载
register_scheduler(app)
三、应用中遇到的问题
遇到的问题1:
使用gunicorn部署项目时,进程数设置的是当前服务器最大workers = multiprocessing.cpu_count() * 2 + 1
,导致一个定时任务会在每个worker进行执行,造成了定时任务重复执行问题
解决办法:
不设置多worker工作,目前单worker工作对项目运行也没有不好的地方
遇到的问题2:
在本地执行定时任务是可以的,但是一上线就发现定时任务不执行了,回来经过查阅资料,也没找到解决办法,一次偶尔机会,发现执行器是使用的线程池进行调度的。
# 配置执行器
"executors": {
# 使用线程池进行调度,最大线程数是20个
'default': ThreadPoolExecutor(20)
},
可能就是在项目构建启动的时候,定时器的线程没有启动起来导致的。
解决办法:
把执行器改成了使用进程池进行调度,问题就解决了。
# 配置执行器
"executors": {
# 使用进程池进行调度,最大进程数是10个
'default': ProcessPoolExecutor(10)
},