diff --git a/tools/browser_launcher.py b/tools/browser_launcher.py index de802a7..011694a 100644 --- a/tools/browser_launcher.py +++ b/tools/browser_launcher.py @@ -14,6 +14,7 @@ import platform import subprocess import time import socket +import signal from typing import Optional, List, Tuple import asyncio from pathlib import Path @@ -106,7 +107,7 @@ class BrowserLauncher: raise RuntimeError(f"无法找到可用的端口,已尝试 {start_port} 到 {port-1}") - def launch_browser(self, browser_path: str, debug_port: int, headless: bool = False, + def launch_browser(self, browser_path: str, debug_port: int, headless: bool = False, user_data_dir: Optional[str] = None) -> subprocess.Popen: """ 启动浏览器进程 @@ -169,7 +170,8 @@ class BrowserLauncher: stderr=subprocess.DEVNULL, preexec_fn=os.setsid # 创建新的进程组 ) - + + self.browser_process = process return process except Exception as e: @@ -230,20 +232,48 @@ class BrowserLauncher: """ 清理资源,关闭浏览器进程 """ - if self.browser_process: - try: - utils.logger.info("[BrowserLauncher] 正在关闭浏览器进程...") - - if self.system == "Windows": - # Windows下使用taskkill强制终止进程树 - subprocess.run(["taskkill", "/F", "/T", "/PID", str(self.browser_process.pid)], - capture_output=True) + if not self.browser_process: + return + + process = self.browser_process + + if process.poll() is not None: + utils.logger.info("[BrowserLauncher] 浏览器进程已退出,无需清理") + self.browser_process = None + return + + utils.logger.info("[BrowserLauncher] 正在关闭浏览器进程...") + + try: + if self.system == "Windows": + # 先尝试正常终止 + process.terminate() + try: + process.wait(timeout=5) + except subprocess.TimeoutExpired: + utils.logger.warning("[BrowserLauncher] 正常终止超时,使用taskkill强制结束") + subprocess.run( + ["taskkill", "/F", "/T", "/PID", str(process.pid)], + capture_output=True, + check=False, + ) + process.wait(timeout=5) + else: + pgid = os.getpgid(process.pid) + try: + os.killpg(pgid, signal.SIGTERM) + except ProcessLookupError: + utils.logger.info("[BrowserLauncher] 浏览器进程组不存在,可能已退出") else: - # Unix系统下终止进程组 - os.killpg(os.getpgid(self.browser_process.pid), 9) - - self.browser_process = None - utils.logger.info("[BrowserLauncher] 浏览器进程已关闭") - - except Exception as e: - utils.logger.warning(f"[BrowserLauncher] 关闭浏览器进程时出错: {e}") + try: + process.wait(timeout=5) + except subprocess.TimeoutExpired: + utils.logger.warning("[BrowserLauncher] 优雅关闭超时,发送SIGKILL") + os.killpg(pgid, signal.SIGKILL) + process.wait(timeout=5) + + utils.logger.info("[BrowserLauncher] 浏览器进程已关闭") + except Exception as e: + utils.logger.warning(f"[BrowserLauncher] 关闭浏览器进程时出错: {e}") + finally: + self.browser_process = None diff --git a/tools/cdp_browser.py b/tools/cdp_browser.py index 5a0ed28..3a29237 100644 --- a/tools/cdp_browser.py +++ b/tools/cdp_browser.py @@ -291,16 +291,28 @@ class CDPBrowserManager: """ try: # 关闭浏览器上下文 - # if self.browser_context: - # await self.browser_context.close() - # self.browser_context = None - # utils.logger.info("[CDPBrowserManager] 浏览器上下文已关闭") + if self.browser_context: + try: + await self.browser_context.close() + utils.logger.info("[CDPBrowserManager] 浏览器上下文已关闭") + except Exception as context_error: + utils.logger.warning( + f"[CDPBrowserManager] 关闭浏览器上下文失败: {context_error}" + ) + finally: + self.browser_context = None - # # 断开浏览器连接 - # if self.browser: - # await self.browser.close() - # self.browser = None - # utils.logger.info("[CDPBrowserManager] 浏览器连接已断开") + # 断开浏览器连接 + if self.browser: + try: + await self.browser.close() + utils.logger.info("[CDPBrowserManager] 浏览器连接已断开") + except Exception as browser_error: + utils.logger.warning( + f"[CDPBrowserManager] 关闭浏览器连接失败: {browser_error}" + ) + finally: + self.browser = None # 关闭浏览器进程(如果配置为自动关闭) if config.AUTO_CLOSE_BROWSER: