fix: multi-tab concurrency and metadata sync improvements

This commit is contained in:
liumangmang
2026-05-30 10:08:55 +08:00
parent 3ab3a5e26f
commit 5268f1119b
3 changed files with 36 additions and 6 deletions
@@ -141,6 +141,8 @@ class BrowserSessionService:
self._sessions[session.id] = session
self._profiles[profile_key] = session.id
self._touch(session.id)
# Register listeners for the initial tab
self._setup_tab_listeners(session, page)
# Register page capture for multi-tab support
context.on("page", lambda p: self._handle_new_page(session, p))
# Evict again after adding the new session so cap is enforced immediately
@@ -160,14 +162,31 @@ class BrowserSessionService:
def _handle_new_page(self, session: BrowserSession, page: Any) -> None:
"""Capture a new page opened by the remote browser (e.g. target="_blank")."""
asyncio.create_task(self._register_new_page(session, page))
def _setup_tab_listeners(self, session: BrowserSession, page: Any) -> None:
"""Register navigation and state listeners to bump tab_revision."""
def bump_revision(_=None):
session.tab_revision += 1
page.on("domcontentloaded", bump_revision)
page.on("load", bump_revision)
page.on("framenavigated", bump_revision)
page.on("close", bump_revision)
async def _register_new_page(self, session: BrowserSession, page: Any) -> None:
tab_id = uuid4().hex
tab = BrowserTab(id=tab_id, page=page, created_at=asyncio.get_event_loop().time())
session.tabs[tab_id] = tab
session.active_tab_id = tab_id
session.tab_revision += 1
logger.info("session %s: captured new tab %s (total: %d)", session.id[:12], tab_id[:8], len(session.tabs))
async with session.lock:
session.tabs[tab_id] = tab
session.active_tab_id = tab_id
session.tab_revision += 1
logger.info("session %s: captured new tab %s (total: %d)", session.id[:12], tab_id[:8], len(session.tabs))
self._setup_tab_listeners(session, page)
# Best-effort: bring to front and reset zoom
asyncio.create_task(self._init_new_tab(session, tab))
await self._init_new_tab(session, tab)
async def _init_new_tab(self, session: BrowserSession, tab: BrowserTab) -> None:
try:
@@ -399,7 +418,8 @@ class BrowserSessionService:
tabs = []
# We might need to prune closed pages during state generation too
closed_ids = []
for tid, tab in session.tabs.items():
# Use list() to avoid RuntimeError if tabs dict changes during iteration
for tid, tab in list(session.tabs.items()):
if tab.page.is_closed():
closed_ids.append(tid)
continue
@@ -734,6 +754,8 @@ class BrowserSessionService:
)
self._sessions[session.id] = session
self._touch(session.id)
# Register listeners for the initial tab
self._setup_tab_listeners(session, page)
# Register page capture
context.on("page", lambda p: self._handle_new_page(session, p))
# Start CDP network capture BEFORE the initial page load,