# app/main.py import os from contextlib import asynccontextmanager from fastapi import FastAPI from dotenv import load_dotenv from apscheduler.schedulers.asyncio import AsyncIOScheduler from app.services.fetcher_service import fetch_and_save_trending_data from app.database import engine from app.models.models import Base # 路由总线 from app.api.router import api_router load_dotenv() CRAWL_INTERVAL = int(os.getenv("CRAWL_INTERVAL_MINUTES", 10)) scheduler = AsyncIOScheduler() # ========================================== # 1. 生命周期管理:App 启动时自动建表 & 启动调度器 # ========================================== @asynccontextmanager async def lifespan(app: FastAPI): # 1. 数据库建表 print("正在初始化数据库表...") Base.metadata.create_all(bind=engine) print("数据库表初始化完成!") # 2. 配置并启动定时任务 scheduler.add_job( fetch_and_save_trending_data, 'interval', minutes=CRAWL_INTERVAL, id='trending_fetch_job', replace_existing=True ) scheduler.start() print(f"定时抓取任务已启动,每 {CRAWL_INTERVAL} 分钟执行一次") # 为了测试方便,启动时立即执行一次 await fetch_and_save_trending_data() yield # 此时 FastAPI 开始接受请求 # 3. 优雅关闭 scheduler.shutdown() print("定时任务已安全关闭") # 初始化 FastAPI app = FastAPI(title="AI 新闻聚合引擎 API", lifespan=lifespan) # ========================================== # 2. 挂载路由总线 # ========================================== # 版本控制 app.include_router(api_router, prefix="/api/v1") # 健康检查 @app.get("/", tags=["健康检查"]) async def root(): return {"message": "Welcome to AI News Aggregator API", "status": "ok"}