fix: avoid blocking browser init

This commit is contained in:
2025-12-18 09:38:02 +08:00
parent 5851120f87
commit 433a3cb806
4 changed files with 108 additions and 17 deletions

View File

@@ -3,6 +3,7 @@
from __future__ import annotations
import threading
import time
from typing import Optional
from app_logger import get_logger
@@ -13,28 +14,99 @@ logger = get_logger("browser_manager")
_browser_manager: Optional[PlaywrightBrowserManager] = None
_lock = threading.Lock()
_cond = threading.Condition(_lock)
_init_in_progress = False
_init_error: Optional[str] = None
_init_thread: Optional[threading.Thread] = None
def get_browser_manager() -> Optional[PlaywrightBrowserManager]:
return _browser_manager
def init_browser_manager() -> bool:
global _browser_manager
def is_browser_manager_ready() -> bool:
return _browser_manager is not None
with _lock:
def get_browser_manager_init_error() -> Optional[str]:
return _init_error
def init_browser_manager(*, block: bool = True, timeout: Optional[float] = None) -> bool:
global _browser_manager
global _init_in_progress, _init_error
deadline = time.monotonic() + float(timeout) if timeout is not None else None
with _cond:
if _browser_manager is not None:
return True
if _init_in_progress:
if not block:
return False
while _init_in_progress:
if deadline is None:
_cond.wait(timeout=0.5)
continue
remaining = deadline - time.monotonic()
if remaining <= 0:
break
_cond.wait(timeout=min(0.5, remaining))
return _browser_manager is not None
_init_in_progress = True
_init_error = None
ok = False
error: Optional[str] = None
manager: Optional[PlaywrightBrowserManager] = None
try:
logger.info("正在初始化Playwright浏览器管理器...")
if not check_and_install_browser(log_callback=lambda msg, account_id=None: logger.info(str(msg))):
error = "浏览器环境检查失败"
logger.error("浏览器环境检查失败!")
return False
ok = False
else:
manager = PlaywrightBrowserManager(
headless=True,
log_callback=lambda msg, account_id=None: logger.info(str(msg)),
)
ok = True
logger.info("Playwright浏览器管理器创建成功")
except Exception as exc:
error = f"{type(exc).__name__}: {exc}"
logger.exception("初始化Playwright浏览器管理器时发生异常")
ok = False
_browser_manager = PlaywrightBrowserManager(
headless=True,
log_callback=lambda msg, account_id=None: logger.info(str(msg)),
)
logger.info("Playwright浏览器管理器创建成功")
return True
with _cond:
if ok and manager is not None:
_browser_manager = manager
else:
_init_error = error or "初始化失败"
_init_in_progress = False
_cond.notify_all()
return ok
def init_browser_manager_async() -> None:
"""异步初始化浏览器环境,避免阻塞 Web 请求/服务启动。"""
global _init_thread
def _worker():
try:
init_browser_manager(block=True)
except Exception:
logger.exception("异步初始化浏览器管理器失败")
with _cond:
if _browser_manager is not None:
return
if _init_thread and _init_thread.is_alive():
return
if _init_in_progress:
return
_init_thread = threading.Thread(target=_worker, daemon=True, name="browser-manager-init")
_init_thread.start()