refactor: web/routers/tasks.py 的 _touch_device 收敛到 services 版

为什么:_touch_device 在 services/tasks.py 与 web/routers/tasks.py 各有一份
逐字相同的实现,且两份都活着。同一份「更新设备心跳时间」的逻辑有两处副本,
改一处忘另一处就会出现行为分叉。

改法:删掉 web 层本地副本(16 行),改为调用 services.tasks._touch_device
(两处调用点),并补 import asyncio 以包裹 to_thread。

说明:上一轮报告里提到的「6 组分叉实现」实测需逐组降级——success()/error()
分属不同层(一个是 tuple 返回、一个是 JSONResponse),iter_content 是两个垫片
的适配器,都**不该**合并;只有 _touch_device 是真·逐字重复,故只收敛这一组。
This commit is contained in:
snowy-yang committed 2026-09-26 18:54:04 +08:00
1 parent 4356c5f817
commit 445c16c329
1 file changed
+4 -14
+4 -14
View File
@@ -12,6 +12,7 @@
这些端点读写 core.state 的共享任务表(与任务执行侧同一批对象),因此 这些端点读写 core.state 的共享任务表(与任务执行侧同一批对象),因此
看到的是同一份任务状态。 看到的是同一份任务状态。
""" """
import asyncio
import time import time
from typing import Annotated, Any from typing import Annotated, Any
@@ -27,6 +28,7 @@ from core.state import (
REQUEST_STATS, REQUEST_STATS,
STATS_LOCK, STATS_LOCK,
) )
from services import tasks as services_tasks
from web import ratelimit from web import ratelimit
from web.deps import SiteUser, require_login from web.deps import SiteUser, require_login
from web.request_utils import ( from web.request_utils import (
@@ -40,18 +42,6 @@ LoginUser = Annotated[SiteUser, Depends(require_login)]
def _touch_device(device_id: str) -> None:
"""记录设备心跳(与 core.state 的 DEVICE_LAST_SEEN 共享)。"""
device_id = str(device_id or '')[:64]
if not device_id:
return
with DEVICE_LAST_SEEN_LOCK:
if len(DEVICE_LAST_SEEN) >= 5000:
for d in sorted(DEVICE_LAST_SEEN, key=lambda k: DEVICE_LAST_SEEN.get(k, 0.0))[:2500]:
DEVICE_LAST_SEEN.pop(d, None)
DEVICE_LAST_SEEN[device_id] = time.time()
def _owned_by(task: dict[str, Any], user: SiteUser) -> bool: def _owned_by(task: dict[str, Any], user: SiteUser) -> bool:
return int(task.get('user_id') or 0) == int(user.id) return int(task.get('user_id') or 0) == int(user.id)
@@ -183,7 +173,7 @@ async def task_heartbeat(user: LoginUser, request: Request):
device_id = str(data.get('device_id') or '').strip()[:64] device_id = str(data.get('device_id') or '').strip()[:64]
if not device_id: if not device_id:
return error('缺少 device_id 参数') return error('缺少 device_id 参数')
_touch_device(device_id) await asyncio.to_thread(services_tasks._touch_device, device_id)
resumed = 0 resumed = 0
with DOWNLOAD_TASKS_LOCK: with DOWNLOAD_TASKS_LOCK:
for task in DOWNLOAD_TASKS.values(): for task in DOWNLOAD_TASKS.values():
@@ -209,7 +199,7 @@ async def task_list(user: LoginUser, request: Request):
device_id = str(data.get('device_id') or '').strip()[:64] device_id = str(data.get('device_id') or '').strip()[:64]
if not device_id: if not device_id:
return error('缺少 device_id 参数') return error('缺少 device_id 参数')
_touch_device(device_id) await asyncio.to_thread(services_tasks._touch_device, device_id)
my_tasks = [] my_tasks = []
with DOWNLOAD_TASKS_LOCK: with DOWNLOAD_TASKS_LOCK:
for tid, task in DOWNLOAD_TASKS.items(): for tid, task in DOWNLOAD_TASKS.items():