fix: 修复 Windows 平台下信号处理器注册问题,避免不必要的注册尝试

This commit is contained in:
DrSmoothl
2026-03-15 16:27:50 +08:00
parent ef11a5fceb
commit e1b3cf6e9f
2 changed files with 41 additions and 9 deletions

View File

@@ -534,6 +534,22 @@ class TestSDK:
class TestPluginSdkUsage: class TestPluginSdkUsage:
"""验证仓库内插件按新 SDK 归一化返回值工作。""" """验证仓库内插件按新 SDK 归一化返回值工作。"""
def test_runner_skips_signal_handler_registration_on_windows(self, monkeypatch):
"""Windows 下不应尝试注册 add_signal_handler。"""
from src.plugin_runtime.runner import runner_main
registered_signals = []
class DummyLoop:
def add_signal_handler(self, sig, callback):
registered_signals.append((sig, callback))
monkeypatch.setattr(runner_main.sys, "platform", "win32")
runner_main._install_shutdown_signal_handlers(lambda: None, DummyLoop())
assert not registered_signals
@pytest.mark.asyncio @pytest.mark.asyncio
async def test_builtin_emoji_plugin_handles_normalized_results(self): async def test_builtin_emoji_plugin_handles_normalized_results(self):
from maibot_sdk.context import PluginContext from maibot_sdk.context import PluginContext

View File

@@ -9,7 +9,7 @@
6. 转发插件的能力调用到 Host 6. 转发插件的能力调用到 Host
""" """
from typing import Any, List, Optional, Protocol, cast from typing import Any, Callable, List, Optional, Protocol, cast
from pathlib import Path from pathlib import Path
@@ -47,6 +47,29 @@ class _ContextAwarePlugin(Protocol):
def _set_context(self, context: Any) -> None: ... def _set_context(self, context: Any) -> None: ...
def _install_shutdown_signal_handlers(
mark_runner_shutting_down: Callable[[], None],
loop: Optional[asyncio.AbstractEventLoop] = None,
) -> None:
"""为 Runner 注册关停信号处理器。
Windows 默认事件循环不支持 add_signal_handler且当前 Runner 在 Windows
下由 Host 直接 terminate/kill不依赖进程内信号回调进行优雅收尾。
"""
if sys.platform == "win32":
return
target_loop = loop or asyncio.get_running_loop()
for sig in (signal.SIGTERM, signal.SIGINT):
try:
target_loop.add_signal_handler(sig, mark_runner_shutting_down)
except Exception as exc:
if not isinstance(exc, (NotImplementedError, RuntimeError)):
raise
logger.debug(f"当前事件循环不支持注册 Runner 信号处理器: {exc}")
return
def _disable_runner_console_logging() -> None: def _disable_runner_console_logging() -> None:
"""关闭 Runner 的控制台日志输出,避免被 Host 从 stderr 二次包装。""" """关闭 Runner 的控制台日志输出,避免被 Host 从 stderr 二次包装。"""
root_logger = stdlib_logging.getLogger() root_logger = stdlib_logging.getLogger()
@@ -666,14 +689,7 @@ async def _async_main() -> None:
def _mark_runner_shutting_down() -> None: def _mark_runner_shutting_down() -> None:
runner._shutting_down = True runner._shutting_down = True
loop = asyncio.get_event_loop() _install_shutdown_signal_handlers(_mark_runner_shutting_down)
for sig in (signal.SIGTERM, signal.SIGINT):
try:
loop.add_signal_handler(sig, _mark_runner_shutting_down)
except NotImplementedError:
logger.warning(f"当前平台/事件循环不支持 signal handler跳过注册信号 {sig!s}")
except RuntimeError as exc:
logger.warning(f"注册信号处理器失败,跳过信号 {sig!s}: {exc}")
await runner.run() await runner.run()