fix: avoid blocking browser init
This commit is contained in:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user