Files
zsglpt/realtime/status_push.py

129 lines
5.6 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from __future__ import annotations
import os
import time
from services.runtime import get_logger, get_socketio
from services.state import safe_get_account, safe_iter_task_status_items
def status_push_worker() -> None:
"""后台线程:按间隔推送排队/运行中任务的状态更新(可节流)。"""
logger = get_logger()
try:
push_interval = float(os.environ.get("STATUS_PUSH_INTERVAL_SECONDS", "1"))
except Exception:
push_interval = 1.0
push_interval = max(0.5, push_interval)
socketio = get_socketio()
from services.tasks import get_task_scheduler
scheduler = get_task_scheduler()
last_queued_emit: dict[str, dict] = {}
while True:
try:
now_ts = time.time()
queue_snapshot = scheduler.get_queue_state_snapshot()
pending_total = int(queue_snapshot.get("pending_total", 0) or 0)
running_total = int(queue_snapshot.get("running_total", 0) or 0)
running_by_user = queue_snapshot.get("running_by_user") or {}
positions = queue_snapshot.get("positions") or {}
status_items = safe_iter_task_status_items()
active_queued_ids: set[str] = set()
for account_id, status_info in status_items:
status = status_info.get("status")
if status not in ("运行中", "排队中"):
continue
user_id = status_info.get("user_id")
if not user_id:
continue
pos = positions.get(account_id) or {}
# 排队中的账号不需要每秒全量推送:仅在队列位置/总数变化或到达保底间隔时推送,避免拖慢整体性能
if status != "运行中":
active_queued_ids.add(account_id)
running_user = int(running_by_user.get(int(user_id), 0) or 0)
prev = last_queued_emit.get(account_id) or {}
prev_ts = float(prev.get("ts", 0) or 0)
should_emit = False
if not prev:
should_emit = True
elif (
prev.get("queue_ahead") != pos.get("queue_ahead")
or prev.get("queue_position") != pos.get("queue_position")
or prev.get("pending_total") != pending_total
or prev.get("running_total") != running_total
or prev.get("running_user") != running_user
):
should_emit = True
elif now_ts - prev_ts >= max(push_interval, 2.0):
should_emit = True
if not should_emit:
continue
last_queued_emit[account_id] = {
"ts": now_ts,
"queue_ahead": pos.get("queue_ahead"),
"queue_position": pos.get("queue_position"),
"pending_total": pending_total,
"running_total": running_total,
"running_user": running_user,
}
else:
last_queued_emit.pop(account_id, None)
account = safe_get_account(user_id, account_id)
if not account:
continue
account_data = account.to_dict()
account_data.update(
{
"queue_pending_total": pending_total,
"queue_running_total": running_total,
"queue_ahead": pos.get("queue_ahead"),
"queue_position": pos.get("queue_position"),
"queue_is_vip": pos.get("is_vip"),
"queue_running_user": int(running_by_user.get(int(user_id), 0) or 0),
}
)
socketio.emit("account_update", account_data, room=f"user_{user_id}")
if status != "运行中":
continue
progress = status_info.get("progress", {}) or {}
progress_data = {
"account_id": account_id,
"stage": status_info.get("detail_status", ""),
"total_items": account.total_items,
"browsed_items": progress.get("items", 0),
"total_attachments": account.total_attachments,
"viewed_attachments": progress.get("attachments", 0),
"start_time": status_info.get("start_time", 0),
"elapsed_seconds": account_data.get("elapsed_seconds", 0),
"elapsed_display": account_data.get("elapsed_display", ""),
"queue_pending_total": pending_total,
"queue_running_total": running_total,
"queue_ahead": pos.get("queue_ahead"),
"queue_position": pos.get("queue_position"),
"queue_running_user": int(running_by_user.get(int(user_id), 0) or 0),
}
socketio.emit("task_progress", progress_data, room=f"user_{user_id}")
# 清理已不在排队的记录,避免 dict 无限制增长
if last_queued_emit:
for acc_id in list(last_queued_emit.keys()):
if acc_id not in active_queued_ids:
last_queued_emit.pop(acc_id, None)
time.sleep(push_interval)
except Exception as e:
logger.debug(f"状态推送出错: {e}")
time.sleep(push_interval)