""" 定时任务接口 - 创建/启动/停止/删除/列表 """ import logging from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from app.database import get_db from app.schemas import ( CreateTaskRequest, TaskInfo, TaskListResponse, ) from app.services.cache import ( create_task, list_tasks, get_task, disable_task, enable_task, delete_task, ) from app.services.scheduler import ( add_job, remove_job, is_job_running, get_all_jobs, ) logger = logging.getLogger(__name__) router = APIRouter(prefix="/tasks", tags=["定时任务"]) @router.post("", response_model=TaskInfo) def create_new_task(req: CreateTaskRequest, db: Session = Depends(get_db)): """ 创建并启动一个定时采集任务。 输入品种合约和轮询时长,自动开始定时获取数据。 """ task = create_task( db=db, symbol=req.symbol, data_type=req.data_type, periods=req.periods, interval_seconds=req.interval_seconds, ) # 注册到调度器 job_id = add_job(task.id, task.interval_seconds) task.job_id = job_id db.commit() db.refresh(task) return _to_task_info(task) @router.get("", response_model=TaskListResponse) def list_all_tasks(db: Session = Depends(get_db)): """列出所有定时任务""" tasks = list_tasks(db) job_status = get_all_jobs() task_infos = [] for t in tasks: running = is_job_running(t.id) if t.enabled else False task_infos.append(TaskInfo( id=t.id, symbol=t.symbol, data_type=t.data_type, periods=t.periods.split(",") if t.periods else [], interval_seconds=t.interval_seconds, enabled=t.enabled, running=running, last_run=t.last_run.isoformat() if t.last_run else None, last_status=t.last_status, created_at=t.created_at.isoformat(), updated_at=t.updated_at.isoformat(), )) return TaskListResponse(tasks=task_infos, total=len(task_infos)) @router.post("/{task_id}/stop", response_model=TaskInfo) def stop_task(task_id: int, db: Session = Depends(get_db)): """停止定时任务(从调度器移除,但保留配置)""" task = get_task(db, task_id) if not task: raise HTTPException(status_code=404, detail=f"任务 {task_id} 不存在") remove_job(task_id) task = disable_task(db, task_id) return _to_task_info(task) @router.post("/{task_id}/start", response_model=TaskInfo) def start_task(task_id: int, db: Session = Depends(get_db)): """重新启动已停止的定时任务""" task = get_task(db, task_id) if not task: raise HTTPException(status_code=404, detail=f"任务 {task_id} 不存在") enable_task(db, task_id) add_job(task.id, task.interval_seconds) db.refresh(task) return _to_task_info(task) @router.delete("/{task_id}") def delete_existing_task(task_id: int, db: Session = Depends(get_db)): """删除定时任务(同时从调度器移除)""" task = get_task(db, task_id) if not task: raise HTTPException(status_code=404, detail=f"任务 {task_id} 不存在") remove_job(task_id) delete_task(db, task_id) return {"message": f"任务 {task_id} 已删除"} @router.post("/{task_id}/update-interval", response_model=TaskInfo) def update_interval( task_id: int, interval_seconds: int, db: Session = Depends(get_db), ): """更新任务的轮询间隔""" task = get_task(db, task_id) if not task: raise HTTPException(status_code=404, detail=f"任务 {task_id} 不存在") task.interval_seconds = interval_seconds task.updated_at = task.updated_at.__class__.now() db.commit() db.refresh(task) # 如果任务正在运行,更新调度器 if task.enabled and is_job_running(task_id): remove_job(task_id) add_job(task.id, task.interval_seconds) return _to_task_info(task) def _to_task_info(task) -> TaskInfo: """ORM -> Pydantic""" return TaskInfo( id=task.id, symbol=task.symbol, data_type=task.data_type, periods=task.periods.split(",") if task.periods else [], interval_seconds=task.interval_seconds, enabled=task.enabled, running=is_job_running(task.id), last_run=task.last_run.isoformat() if task.last_run else None, last_status=task.last_status, created_at=task.created_at.isoformat(), updated_at=task.updated_at.isoformat(), )