fix(database): decouple worker errors from application

This commit is contained in:
InfinityPacer
2026-08-23 14:26:42 +08:00
parent d16ceb5804
commit d2b72f5729
14 changed files with 53 additions and 32 deletions
+13 -7
View File
@@ -2467,14 +2467,15 @@ class PluginHelper(metaclass=WeakSingleton):
"""异步恢复主程序运行依赖,避免修复命令绕过可取消进程边界。"""
repair_target = snapshot_file
repair_desc = "主程序依赖快照"
if repair_target and not repair_target.exists():
if repair_target and not await _await_thread_operation(repair_target.exists):
repair_target = None
if repair_target is None:
repair_target = settings.ROOT_PATH / "pyproject.toml"
repair_desc = "主程序 uv.lock"
if not repair_target.exists():
if not await _await_thread_operation(repair_target.exists):
return False, f"恢复依赖文件不存在:{repair_target}"
if snapshot_file is None and not (settings.ROOT_PATH / "uv.lock").exists():
lock_file = settings.ROOT_PATH / "uv.lock"
if snapshot_file is None and not await _await_thread_operation(lock_file.exists):
return False, f"恢复依赖文件不存在:{settings.ROOT_PATH / 'uv.lock'}"
request = cls.__build_package_install_request(
@@ -2568,7 +2569,7 @@ class PluginHelper(metaclass=WeakSingleton):
candidate_dirs = []
for dependency_file in resolved_dependency_files:
wheels_dir = dependency_file.parent / "wheels"
if wheels_dir.is_dir():
if await _await_thread_operation(wheels_dir.is_dir):
candidate_dirs.append(wheels_dir)
if find_links_dirs:
candidate_dirs.extend(find_links_dirs)
@@ -2577,9 +2578,11 @@ class PluginHelper(metaclass=WeakSingleton):
seen_dirs = set()
for candidate_dir in candidate_dirs:
candidate_path = Path(candidate_dir)
if not candidate_path.is_dir():
if not await _await_thread_operation(candidate_path.is_dir):
continue
candidate_key = str(candidate_path.resolve())
candidate_key = str(
await _await_thread_operation(candidate_path.resolve)
)
if candidate_key in seen_dirs:
continue
seen_dirs.add(candidate_key)
@@ -2707,7 +2710,10 @@ class PluginHelper(metaclass=WeakSingleton):
if acquired:
cls._package_install_lock.release()
if constraints_file:
constraints_file.unlink(missing_ok=True)
await _await_thread_operation(
constraints_file.unlink,
missing_ok=True,
)
async def __async_backup_plugin(self, pid: str) -> str:
"""
+1 -1
View File
@@ -57,7 +57,7 @@ from app.api.dependencies.plugin import (
from app.adapters.external.server import MoviePilotServerHelper
from app.adapters.external.market import PluginHelper
from app.adapters.system.plugin.package import PluginPackageManager
from app.application.database import DatabaseWorkerOverloadedError
from app.schemas.exception import DatabaseWorkerOverloadedError
from app.runtime.log import logger
from app.schemas.types import SystemConfigKey
-8
View File
@@ -18,14 +18,6 @@ DatabaseProbe = Callable[[], Optional[str]]
T = TypeVar("T")
class DatabaseWorkerClosedError(RuntimeError):
"""数据库执行器尚未启动或已经停止。"""
class DatabaseWorkerOverloadedError(RuntimeError):
"""数据库执行器的运行与排队容量已经用尽。"""
class AsyncDatabaseExecutor(Protocol):
"""让异步业务调用同步短事务而不阻塞事件循环。"""
+3 -1
View File
@@ -10,10 +10,12 @@ from weakref import WeakValueDictionary
from app.application.database import (
AsyncDatabaseExecutor,
)
from app.schemas.agent import AgentChatSessionDetail, AgentChatSessionSummary
from app.schemas.exception import (
DatabaseWorkerClosedError,
DatabaseWorkerOverloadedError,
)
from app.schemas.agent import AgentChatSessionDetail, AgentChatSessionSummary
from app.runtime.observability import record_metric
+1 -1
View File
@@ -7,7 +7,7 @@ from collections.abc import Awaitable, Callable
from dataclasses import dataclass, field
from typing import Any, Optional
from app.application.database import DatabaseWorkerOverloadedError
from app.schemas.exception import DatabaseWorkerOverloadedError
from app.application.plugin.lifecycle import plugin_lifecycle
from app.runtime.log import logger
+1 -1
View File
@@ -10,7 +10,7 @@ from contextvars import copy_context
from dataclasses import dataclass
from typing import Callable, TypeVar
from app.application.database import (
from app.schemas.exception import (
DatabaseWorkerClosedError,
DatabaseWorkerOverloadedError,
)
+1 -1
View File
@@ -14,7 +14,7 @@ from app.adapters.observability.otel import build_observation_port
from app.adapters.web.plugin.routes import FastAPIDynamicRouteRegistry
from app.adapters.web.health import install_health_routes
from app.application.plugin.routes import configure_plugin_routes
from app.application.database import (
from app.schemas.exception import (
DatabaseWorkerClosedError,
DatabaseWorkerOverloadedError,
)
+8
View File
@@ -47,6 +47,14 @@ class StorageQueryError(Exception):
pass
class DatabaseWorkerClosedError(RuntimeError):
"""数据库执行器尚未启动或已经停止。"""
class DatabaseWorkerOverloadedError(RuntimeError):
"""数据库执行器的运行与排队容量已经用尽。"""
class TMDbException(Exception):
"""
用于表示TheMovieDB数据源请求失败的跨层异常契约。
+2
View File
@@ -81,6 +81,8 @@ SCHEMA_EXPORTS = {
'DashboardMemoryInfo': ('app.schemas.dashboard', 'DashboardMemoryInfo'),
'DashboardSystemInfo': ('app.schemas.dashboard', 'DashboardSystemInfo'),
'DataT': ('app.schemas.response', 'DataT'),
'DatabaseWorkerClosedError': ('app.schemas.exception', 'DatabaseWorkerClosedError'),
'DatabaseWorkerOverloadedError': ('app.schemas.exception', 'DatabaseWorkerOverloadedError'),
'Dict': ('app.schemas.mcp', 'Dict'),
'DiscoverMediaSource': ('app.schemas.event', 'DiscoverMediaSource'),
'DiscoverSourceEventData': ('app.schemas.event', 'DiscoverSourceEventData'),