from typing import List from datetime import datetime from fastapi import APIRouter, Depends, HTTPException, BackgroundTasks from sqlalchemy.orm import Session from croniter import croniter from app.core.database import get_db from app.models.schedule import Schedule from app.schemas.schedule import ScheduleResponse, ScheduleUpdate, ScheduleLogResponse router = APIRouter(prefix="/schedules", tags=["schedules"]) @router.get("", response_model=List[ScheduleResponse]) def list_schedules(db: Session = Depends(get_db)): return db.query(Schedule).order_by(Schedule.id).all() @router.get("/{schedule_id}", response_model=ScheduleResponse) def get_schedule(schedule_id: int, db: Session = Depends(get_db)): s = db.get(Schedule, schedule_id) if not s: raise HTTPException(status_code=404, detail="Schedule not found") return s @router.put("/{schedule_id}", response_model=ScheduleResponse) def update_schedule_cron(schedule_id: int, payload: ScheduleUpdate, db: Session = Depends(get_db)): s = db.get(Schedule, schedule_id) if not s: raise HTTPException(status_code=404, detail="Schedule not found") # Validate cron expression try: cron = croniter(payload.cron_timer, datetime.utcnow()) next_run = cron.get_next(datetime) except Exception: raise HTTPException(status_code=422, detail="Invalid cron expression") s.cron_timer = payload.cron_timer s.next_run_at = next_run db.commit() db.refresh(s) return s @router.post("/{schedule_id}/run", status_code=202) def manual_run(schedule_id: int, background_tasks: BackgroundTasks, db: Session = Depends(get_db)): """手動觸發排程(非同步執行)""" s = db.get(Schedule, schedule_id) if not s: raise HTTPException(status_code=404, detail="Schedule not found") if s.status == "Going": raise HTTPException(status_code=409, detail="Schedule is already running") from app.services.scheduler.runner import dispatch_schedule background_tasks.add_task(dispatch_schedule, schedule_id) return {"message": f"Schedule '{s.name}' triggered", "schedule_id": schedule_id} @router.get("/{schedule_id}/logs", response_model=List[ScheduleLogResponse]) def get_schedule_logs(schedule_id: int, limit: int = 20, db: Session = Depends(get_db)): from app.models.schedule import ScheduleLog logs = ( db.query(ScheduleLog) .filter(ScheduleLog.schedule_id == schedule_id) .order_by(ScheduleLog.started_at.desc()) .limit(limit) .all() ) return logs