refactor: expand async and type safety gates

This commit is contained in:
jxxghp
2026-08-22 13:21:52 +08:00
parent 677f6a66c2
commit 7bc5e01afd
12 changed files with 103 additions and 33 deletions
+11 -2
View File
@@ -2772,8 +2772,11 @@ class PluginHelper(metaclass=WeakSingleton):
await async_dest_path.mkdir(parents=True, exist_ok=True)
continue
await async_dest_path.parent.mkdir(parents=True, exist_ok=True)
with zf.open(info, 'r') as src:
data = src.read()
data = await asyncio.to_thread(
self.__read_release_zip_member,
zf,
info,
)
async with aiofiles.open(dest_path, 'wb') as dst:
await dst.write(data)
wrote_any = True
@@ -2784,6 +2787,12 @@ class PluginHelper(metaclass=WeakSingleton):
logger.error(f"解压 Release 压缩包失败:{e}")
return False, f"解压 Release 压缩包失败:{e}"
@staticmethod
def __read_release_zip_member(zf: zipfile.ZipFile, info: zipfile.ZipInfo) -> bytes:
"""在线程池读取并解压单个 Release 文件,避免阻塞事件循环。"""
with zf.open(info, "r") as source:
return source.read()
# 公开 Release 查询的缓存管理统一指向仓库级分页缓存。
PluginHelper.get_plugin_release_versions.cache_clear = PluginHelper._get_plugin_repo_releases.cache_clear
+17 -6
View File
@@ -87,6 +87,17 @@ SUMMARY_PROMPT = """请判断以下 AI 助手与用户的对话是否值得写
ACTIVITY_ENTRY_PATTERN = re.compile(r"^-\s+\*\*(?P<time>\d{2}:\d{2})\*\*\s+(?P<summary>.+)$")
def _write_activity_log_exclusive(path: Path, content: str) -> bool:
"""同步独占创建日志文件;调用方必须在线程池中执行本函数。"""
try:
fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644)
except FileExistsError:
return False
with os.fdopen(fd, "w", encoding="utf-8") as stream:
stream.write(content)
return True
class QueryActivityLogInput(BaseModel):
"""查询活动日志工具的输入参数模型。"""
@@ -565,18 +576,18 @@ class ActivityLogMiddleware(AgentMiddleware[ActivityLogState, ContextT, Response
await stream.write(entry)
else:
header = f"# {today_str} 活动日志\n\n"
try:
fd = os.open(log_path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644)
except FileExistsError:
created = await anyio.to_thread.run_sync(
_write_activity_log_exclusive,
Path(log_path),
header + entry,
)
if not created:
async with await anyio.open_file(
log_path,
mode="a",
encoding="utf-8",
) as stream:
await stream.write(entry)
else:
with os.fdopen(fd, "w", encoding="utf-8") as stream:
stream.write(header + entry)
logger.debug(f"Activity logged: {summarize_result(summary, max_chars=80)}")
except Exception as e:
logger.warning(f"Failed to append activity log: {summarize_error(e)}")
+2 -2
View File
@@ -16,7 +16,7 @@ from app.api.context import (
from app.api.data import get_async_db, get_db
from app.api.dependencies.data import repository
from app.application.outbox import AsyncOutboxTransaction
from app.application.scheduling import Scheduler
from app.application.scheduling import start_scheduler_job
from app.application.servarr import ServarrSubscriptionService
from app.application.subscription.delete import (
AsyncUnitOfWork as DeleteUnitOfWork,
@@ -99,7 +99,7 @@ def get_search_subscriptions_command(
def schedule_search(subscribe_id: int | None, state: str | None) -> None:
"""按历史参数提交订阅搜索调度任务。"""
background_tasks.add_task(
Scheduler().start,
start_scheduler_job,
job_id="subscribe_search",
sid=subscribe_id,
state=state,
+5 -5
View File
@@ -12,7 +12,7 @@ Scheduler 实现由 startup 组合根在导入期注册,避免 application 层
import asyncio
from dataclasses import dataclass, field
from enum import StrEnum
from typing import Any, Awaitable, Callable, List, Optional
from typing import Any, Awaitable, Callable, List, Optional, cast
# Agent 自主定时任务在运行时调度器中的任务 ID 前缀。
AGENT_TASK_JOB_PREFIX = "agent-task"
@@ -143,12 +143,12 @@ class Scheduler:
def list_scheduler_jobs() -> List[Any]:
"""列出运行时调度器的全部任务。"""
return get_scheduler().list()
return cast(List[Any], get_scheduler().list())
def start_scheduler_job(job_id: str) -> None:
def start_scheduler_job(job_id: str, **kwargs: Any) -> None:
"""立即运行指定的运行时定时任务。"""
get_scheduler().start(job_id)
get_scheduler().start(job_id, **kwargs)
def update_plugin_job(plugin_id: str) -> None:
@@ -163,7 +163,7 @@ def remove_plugin_job(plugin_id: str) -> None:
def start_agent_task(task_id: int) -> bool:
"""立即执行 Agent 自主定时任务。"""
return get_scheduler().start_agent_task(task_id)
return cast(bool, get_scheduler().start_agent_task(task_id))
def get_agent_task_next_run(task_id: int) -> Optional[Any]:
+1 -1
View File
@@ -20,7 +20,7 @@ class EventErrorPolicy:
self,
*,
notifier: Callable[[], Optional[EventErrorNotifier]],
emit_system_error: Callable[[dict], object],
emit_system_error: Callable[[dict[str, Any]], object],
) -> None:
"""注入通知读取器和 SystemError 发送回调。"""
self._notifier = notifier
+2 -2
View File
@@ -4,7 +4,7 @@ from __future__ import annotations
import inspect
from collections.abc import Callable, Mapping
from typing import Any, Protocol
from typing import Any, Protocol, cast
from app.foundation.reflection import ObjectUtils
from app.runtime.execution import run_in_threadpool
@@ -324,7 +324,7 @@ class ModuleInvocationDispatcher:
def _module_name(module: Any, fallback: str) -> str:
"""读取模块展示名,失败时回退到稳定类名。"""
try:
return module.get_name()
return cast(str, module.get_name())
except Exception as err:
logger.debug("获取模块名称出错:%s", str(err))
return fallback