fix(browser): suppress KeyboardInterrupt in atexit cleanup thread stop
A second Ctrl+C while the atexit hook joins the browser janitor thread surfaced as "Exception ignored in atexit callback: _stop_browser_cleanup_thread" with a KeyboardInterrupt traceback. The janitor is a daemon thread and the interpreter is already exiting, so nothing is lost by swallowing the interrupt — the terminal tool's sibling _stop_cleanup_thread already does. Salvaged from #10765 (function has since moved to browser_tool_lifecycle.py). Fixes #10764 Co-authored-by: LehaoLin <lehaolin98@outlook.com>
This commit is contained in:
@@ -187,3 +187,19 @@ class TestInactivityJanitorMultiplex:
|
||||
assert "t1" not in self.bt._active_sessions
|
||||
assert "t1" not in self.bt._session_last_activity
|
||||
assert "t1" not in self.bt._cleanup_failures
|
||||
|
||||
|
||||
class TestAtexitStopSwallowsInterrupt:
|
||||
def test_second_ctrl_c_during_join_does_not_propagate(self, monkeypatch):
|
||||
"""A second Ctrl+C while the atexit hook waits on the janitor must not escape as a
|
||||
traceback (#10764): the thread is a daemon, the interpreter is already exiting."""
|
||||
from tools import browser_tool
|
||||
|
||||
class _InterruptedJoin:
|
||||
def join(self, timeout=None):
|
||||
raise KeyboardInterrupt
|
||||
|
||||
monkeypatch.setattr(browser_tool, "_cleanup_thread", _InterruptedJoin())
|
||||
monkeypatch.setattr(browser_tool, "_cleanup_running", True)
|
||||
bt_lifecycle._stop_browser_cleanup_thread() # must not raise
|
||||
assert browser_tool._cleanup_running is False
|
||||
|
||||
@@ -424,7 +424,12 @@ def _stop_browser_cleanup_thread():
|
||||
"""Stop the background cleanup thread."""
|
||||
_bt._cleanup_running = False
|
||||
if _bt._cleanup_thread is not None:
|
||||
_bt._cleanup_thread.join(timeout=5)
|
||||
# A second Ctrl+C during the timed join lands here as KeyboardInterrupt; the janitor is a
|
||||
# daemon thread, so letting it propagate only prints "Exception ignored in atexit callback".
|
||||
try:
|
||||
_bt._cleanup_thread.join(timeout=5)
|
||||
except (SystemExit, KeyboardInterrupt):
|
||||
pass
|
||||
|
||||
|
||||
def _update_session_activity(task_id: str):
|
||||
|
||||
Reference in New Issue
Block a user