fix: remove browser_tool signal handlers that cause voice mode deadlock

browser_tool.py registered SIGINT/SIGTERM handlers that called sys.exit()
at module import time. When a signal arrived during a lock acquisition
(e.g. AudioRecorder._lock in voice mode), SystemExit was raised inside
prompt_toolkit's async event loop, corrupting coroutine state and making
the process unkillable (required SIGKILL).

atexit handler already ensures browser sessions are cleaned up on any
normal exit path, so the signal handlers were redundant and harmful.
This commit is contained in:
0xbyt4 2026-03-10 12:39:13 +03:00
parent ddfd6e0c59
commit 6e51729c4c
2 changed files with 33 additions and 16 deletions

View file

@ -224,24 +224,14 @@ def _emergency_cleanup_all_sessions():
logger.error("Emergency cleanup error: %s", e)
def _signal_handler(signum, frame):
"""Handle interrupt signals to cleanup sessions before exit."""
logger.warning("Received signal %s, cleaning up...", signum)
_emergency_cleanup_all_sessions()
sys.exit(128 + signum)
# Register cleanup handlers
# Register cleanup via atexit only. Previous versions installed SIGINT/SIGTERM
# handlers that called sys.exit(), but this conflicts with prompt_toolkit's
# async event loop — a SystemExit raised inside a key-binding callback
# corrupts the coroutine state and makes the process unkillable. atexit
# handlers run on any normal exit (including sys.exit), so browser sessions
# are still cleaned up without hijacking signals.
atexit.register(_emergency_cleanup_all_sessions)
# Only register signal handlers in main process (not in multiprocessing workers)
try:
if os.getpid() == os.getpgrp(): # Main process check
signal.signal(signal.SIGINT, _signal_handler)
signal.signal(signal.SIGTERM, _signal_handler)
except (OSError, AttributeError):
pass # Signal handling not available (e.g., Windows or worker process)
# =============================================================================
# Inactivity Cleanup Functions