You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

162 lines
4.5 KiB

"""
定时任务接口 - 创建/启动/停止/删除/列表
"""
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(),
)