infra/stacks/f1-stream/files/backend/main.py
Viktor Barzin becf56a013 [ci skip] f1-stream: add F1 schedule subsystem (Phase 2)
- Fetch 2026 F1 race calendar from jolpica API with all sessions
  (FP1-3, Qualifying, Sprint, Race) and UTC timestamps
- Persist schedule to NFS as JSON, load on startup if fresh
- APScheduler daily refresh at 03:00 UTC
- GET /schedule endpoint with live/upcoming/past session status
- POST /schedule/refresh for manual refresh trigger
2026-02-23 22:55:13 +00:00

80 lines
2 KiB
Python

"""F1 Streams - FastAPI backend with schedule service."""
import logging
from contextlib import asynccontextmanager
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.cron import CronTrigger
from fastapi import FastAPI
from backend.schedule import ScheduleService
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s %(levelname)s %(name)s: %(message)s",
)
logger = logging.getLogger(__name__)
schedule_service = ScheduleService()
scheduler = AsyncIOScheduler()
async def _scheduled_refresh() -> None:
"""Callback for APScheduler daily refresh."""
logger.info("Running scheduled schedule refresh...")
await schedule_service.refresh()
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Startup and shutdown lifecycle handler."""
# Startup: load schedule and start background scheduler
await schedule_service.initialize()
scheduler.add_job(
_scheduled_refresh,
trigger=CronTrigger(hour=3, minute=0, timezone="UTC"),
id="daily_schedule_refresh",
name="Refresh F1 schedule daily at 03:00 UTC",
replace_existing=True,
)
scheduler.start()
logger.info("APScheduler started - daily refresh at 03:00 UTC")
yield
# Shutdown
scheduler.shutdown(wait=False)
logger.info("APScheduler shut down")
app = FastAPI(title="F1 Streams", lifespan=lifespan)
@app.get("/health")
async def health():
return {"status": "ok"}
@app.get("/")
async def root():
return {"service": "f1-streams", "version": "2.0.1"}
@app.get("/schedule")
async def get_schedule():
"""Return the F1 race schedule for the current season with session statuses."""
return schedule_service.get_schedule()
@app.post("/schedule/refresh")
async def refresh_schedule():
"""Manually trigger a schedule refresh from the jolpica API."""
await schedule_service.refresh()
return {"status": "refreshed"}
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)