fastapi apscheduler 集成简单说明
对于 fastapi apscheduler 集成以及支持动态添加任务的简单说明
参考使用
- 依赖
包含了fastapi,apscheduler sqlalchemy uvicorn
pip install fastapi apscheduler sqlalchemy uvicorn
- 代码简单说明
代码使用了基于数据库jobstores,同时演示了一个简单的编程模式添加job(动态加载模块方式)以及基于配置的job 初始化
yaml 格式配置的job 定义
version: v1
tasks:
- name: baidu
modulename: mytask
taskname: task
interval: 5
- name: google
modulename: mytaskv2
taskname: task
interval: 5
fastapi 集成代码
from fastapi import FastAPI
from apscheduler.schedulers.asyncio import AsyncIOScheduler as Scheduler
from apscheduler.triggers.interval import IntervalTrigger
from importlib import import_module
from contextlib import asynccontextmanager
import logging
logging.basicConfig()
logging.getLogger('apscheduler').setLevel(logging.DEBUG)
from apscheduler.jobstores.sqlalchemy import SQLAlchemyJobStore
from sqlalchemy import create_engine
from config import config
from apscheduler.events import EVENT_ALL,JobEvent
# Database URL
DATABASE_URL = "sqlite:///./test.db"
# Create the database engine
engine = create_engine(DATABASE_URL)
# Configure the job store
jobstores = {
'default': SQLAlchemyJobStore(engine=engine)
}
scheduler = Scheduler(jobstores=jobstores)
def listener(event:JobEvent) -> None:
print(event)
@asynccontextmanager
async def lifespan(app: FastAPI):
myconfig = config()
app.state.scheduler = scheduler
scheduler.add_listener(listener, EVENT_ALL)
for task in myconfig.tasks:
module = import_module(task.get('modulename'))
interval = task.get('interval')
print("interval", interval)
scheduler.add_job(getattr(module, task.get('taskname')), IntervalTrigger(seconds=interval))
scheduler.start()
yield
app.state.scheduler.shutdown()
app = FastAPI(lifespan=lifespan)
@app.get("/")
async def read_root():
return {"message": "Hello World"}
@app.get("/lists")
async def tasklists():
return [ item.id for item in scheduler.get_jobs() ]
@app.get("/add")
async def addtask():
module = import_module("mytaskv3")
interval = 3
task = getattr(module, "task")
# 动态加载模式
job = scheduler.add_job(task,IntervalTrigger(seconds=interval),name="mydemo",id="mydemo")
return dict(id=job.id, name=job.name, next_run_time=job.next_run_time)
if __name__ == "__main__":
import uvicorn
try:
uvicorn.run(app, host="0.0.0.0", port=8000)
except KeyboardInterrupt as e:
print(e)
动态加载简单说明,核心是对于开发好的任务通过import_module 进行模块加载,之后通过属性获取实际的任务方法
说明
注意目前使用的apscheduler 版本是3.10.4 当前4.0 版本还处于预发布阶段,很多使用上变化还是比较大的,目前apscheduler 对于任务依赖上是缺少支持的,也是可以做,但是并不是很方便,此场景rocketry 是一个不错的选择,但是目前看着是缺少维护了,从使用上两个实际上可以配置起来使用,可以解决一些依赖的问题
参考资料
https://github.com/agronholm/apscheduler
https://fastapi.tiangolo.com/advanced/events/
https://apscheduler.readthedocs.io/en/3.x/versionhistory.html
https://github.com/Miksus/rocketry