feat: 增强任务进度透明化
This commit is contained in:
@@ -2,6 +2,7 @@ import inspect
|
||||
import json
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from collections.abc import Callable
|
||||
from datetime import UTC, datetime
|
||||
|
||||
from sqlalchemy import func, select
|
||||
from sqlalchemy.orm import Session, sessionmaker
|
||||
@@ -19,6 +20,7 @@ from app.services.report_service import generate_hotspot_report, generate_item_r
|
||||
|
||||
RUNNING_TASK_MESSAGE = "当前有正在运行的任务,请稍后再试"
|
||||
RESTART_ERROR_MESSAGE = "系统重启,任务被中断"
|
||||
STALE_PROGRESS_THRESHOLD_SECONDS = 10 * 60
|
||||
task_executor = ThreadPoolExecutor(max_workers=1)
|
||||
|
||||
|
||||
@@ -148,6 +150,7 @@ def get_task(session: Session, task_id: str) -> Task | None:
|
||||
|
||||
|
||||
def hydrate_task_progress(session: Session, task: Task) -> Task:
|
||||
task.hotspots_count = session.scalar(select(func.count(Hotspot.id)).where(Hotspot.task_id == task.id)) or 0
|
||||
task.comments_count = session.scalar(select(func.count(Comment.id)).where(Comment.task_id == task.id)) or 0
|
||||
task.reports_count = session.scalar(select(func.count(Report.id)).where(Report.task_id == task.id)) or 0
|
||||
task.is_demo = task.id.startswith("demo-")
|
||||
@@ -160,9 +163,51 @@ def hydrate_task_progress(session: Session, task: Task) -> Task:
|
||||
elif not stage_code and task.status == "running":
|
||||
stage_code = "queued"
|
||||
task.current_stage_label = STAGE_LABELS.get(stage_code or "", stage_code or "等待启动")
|
||||
now = ensure_utc_datetime(utc_now())
|
||||
running_start = ensure_utc_datetime(task.started_at or task.created_at)
|
||||
running_end = ensure_utc_datetime(task.finished_at) or now
|
||||
last_progress_at = ensure_utc_datetime(task.last_progress_at)
|
||||
running_seconds = max(0, int((running_end - running_start).total_seconds()))
|
||||
seconds_since_progress = max(0, int((now - last_progress_at).total_seconds())) if last_progress_at else None
|
||||
task.running_seconds = running_seconds
|
||||
task.seconds_since_last_progress = seconds_since_progress
|
||||
task.running_duration_label = format_duration_zh(running_seconds)
|
||||
task.last_progress_ago_label = f"{format_duration_zh(seconds_since_progress)}前" if seconds_since_progress is not None else "暂无记录"
|
||||
task.stale_threshold_minutes = STALE_PROGRESS_THRESHOLD_SECONDS // 60
|
||||
task.is_progress_stale = (
|
||||
task.status == "running"
|
||||
and seconds_since_progress is not None
|
||||
and seconds_since_progress >= STALE_PROGRESS_THRESHOLD_SECONDS
|
||||
)
|
||||
return task
|
||||
|
||||
|
||||
def format_duration_zh(total_seconds: int | None) -> str:
|
||||
if total_seconds is None:
|
||||
return "暂无记录"
|
||||
total_seconds = max(0, int(total_seconds))
|
||||
minutes = total_seconds // 60
|
||||
hours = minutes // 60
|
||||
days = hours // 24
|
||||
if days > 0:
|
||||
remaining_hours = hours % 24
|
||||
return f"{days}天{remaining_hours}小时" if remaining_hours else f"{days}天"
|
||||
if hours > 0:
|
||||
remaining_minutes = minutes % 60
|
||||
return f"{hours}小时{remaining_minutes}分钟" if remaining_minutes else f"{hours}小时"
|
||||
if minutes > 0:
|
||||
return f"{minutes}分钟"
|
||||
return "刚刚"
|
||||
|
||||
|
||||
def ensure_utc_datetime(value: datetime | None) -> datetime | None:
|
||||
if value is None:
|
||||
return None
|
||||
if value.tzinfo is None:
|
||||
return value.replace(tzinfo=UTC)
|
||||
return value.astimezone(UTC)
|
||||
|
||||
|
||||
def update_task_stage(task: Task, stage: str) -> None:
|
||||
task.current_stage = stage
|
||||
task.last_progress_at = utc_now()
|
||||
|
||||
Reference in New Issue
Block a user