From 83e4bae7db493d7726411ddecd8b4fe96aeec3f5 Mon Sep 17 00:00:00 2001 From: Xubin Ren <52506698+Re-bin@users.noreply.github.com> Date: Sat, 4 Jul 2026 21:11:18 +0800 Subject: [PATCH] fix(gateway): skip ctrl-break wait when signal is rejected --- nanobot/gateway/runtime.py | 11 +++++++++-- tests/gateway/test_runtime.py | 3 +++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/nanobot/gateway/runtime.py b/nanobot/gateway/runtime.py index 47f06e7e..7acd878f 100644 --- a/nanobot/gateway/runtime.py +++ b/nanobot/gateway/runtime.py @@ -295,9 +295,16 @@ class GatewayRuntime: if ctrl_break is not None: # Detached Windows children can reject CTRL_BREAK_EVENT with WinError 87; # keep the existing taskkill fallback for that process shape. - with suppress(ProcessLookupError, OSError): + ctrl_break_sent = False + try: os.kill(pid, ctrl_break) - if self._wait_for_exit(pid, timeout_s): + except ProcessLookupError: + return True + except OSError: + pass + else: + ctrl_break_sent = True + if ctrl_break_sent and self._wait_for_exit(pid, timeout_s): return True self._subprocess_run( ["taskkill", "/PID", str(pid), "/T"], diff --git a/tests/gateway/test_runtime.py b/tests/gateway/test_runtime.py index e79aa3e4..5643d17b 100644 --- a/tests/gateway/test_runtime.py +++ b/tests/gateway/test_runtime.py @@ -174,6 +174,7 @@ def test_stop_keeps_state_when_process_survives_timeout(tmp_path, monkeypatch): def test_terminate_windows_falls_back_when_ctrl_break_is_rejected(tmp_path, monkeypatch): taskkill_calls: list[dict] = [] + wait_timeouts: list[int | float] = [] def fake_run(command, **kwargs): taskkill_calls.append({"command": command, "kwargs": kwargs}) @@ -193,12 +194,14 @@ def test_terminate_windows_falls_back_when_ctrl_break_is_rejected(tmp_path, monk monkeypatch.setattr("nanobot.gateway.runtime.os.kill", fake_kill) def fake_wait_for_exit(_pid, _timeout_s): + wait_timeouts.append(_timeout_s) # Simulate a process that only exits after the taskkill fallback runs. return bool(taskkill_calls) monkeypatch.setattr(runtime, "_wait_for_exit", fake_wait_for_exit) assert runtime._terminate_windows(12345, timeout_s=20) is True + assert wait_timeouts == [2] assert taskkill_calls == [ { "command": ["taskkill", "/PID", "12345", "/T"],