diff --git a/browser_use/agent/service.py b/browser_use/agent/service.py index e6a2fbee6..888059458 100644 --- a/browser_use/agent/service.py +++ b/browser_use/agent/service.py @@ -1226,9 +1226,12 @@ class Agent(Generic[Context, AgentStructuredOutput]): if self._is_connection_like_error(error): # If reconnection is in progress, wait for it instead of stopping if self.browser_session.is_reconnecting: - self.logger.warning(f'🔄 Connection error during reconnection, waiting for reconnect: {error}') + wait_timeout = self.browser_session.RECONNECT_WAIT_TIMEOUT + self.logger.warning( + f'🔄 Connection error during reconnection, waiting up to {wait_timeout}s for reconnect: {error}' + ) try: - await asyncio.wait_for(self.browser_session._reconnect_event.wait(), timeout=20.0) + await asyncio.wait_for(self.browser_session._reconnect_event.wait(), timeout=wait_timeout) except TimeoutError: pass diff --git a/browser_use/browser/session.py b/browser_use/browser/session.py index e0ebf7f42..d12e246d4 100644 --- a/browser_use/browser/session.py +++ b/browser_use/browser/session.py @@ -517,6 +517,9 @@ class BrowserSession(BaseModel): _demo_mode: 'DemoMode | None' = PrivateAttr(default=None) # WebSocket reconnection state + # Max wait = attempts * timeout_per_attempt + sum(delays) + small buffer + # Default: 3 * 15s + (1+2+4)s + 2s = 54s + RECONNECT_WAIT_TIMEOUT: float = 54.0 _reconnecting: bool = PrivateAttr(default=False) _reconnect_event: asyncio.Event = PrivateAttr(default_factory=asyncio.Event) _reconnect_lock: asyncio.Lock = PrivateAttr(default_factory=asyncio.Lock) diff --git a/browser_use/browser/watchdog_base.py b/browser_use/browser/watchdog_base.py index 356bcf5c4..622e6bc78 100644 --- a/browser_use/browser/watchdog_base.py +++ b/browser_use/browser/watchdog_base.py @@ -98,14 +98,16 @@ class BaseWatchdog(BaseModel): if event.event_type not in LIFECYCLE_EVENT_NAMES and not browser_session.is_cdp_connected: # If reconnection is in progress, wait for it instead of silently skipping if browser_session.is_reconnecting: + wait_timeout = browser_session.RECONNECT_WAIT_TIMEOUT browser_session.logger.debug( - f'🚌 [{watchdog_class_name}.{actual_handler.__name__}] ⏳ Waiting for reconnection...' + f'🚌 [{watchdog_class_name}.{actual_handler.__name__}] ⏳ Waiting for reconnection ({wait_timeout}s)...' ) try: - await asyncio.wait_for(browser_session._reconnect_event.wait(), timeout=20.0) + await asyncio.wait_for(browser_session._reconnect_event.wait(), timeout=wait_timeout) except TimeoutError: raise ConnectionError( - f'[{watchdog_class_name}.{actual_handler.__name__}] Reconnection wait timed out after 20s' + f'[{watchdog_class_name}.{actual_handler.__name__}] ' + f'Reconnection wait timed out after {wait_timeout}s' ) # After wait: check if reconnection actually succeeded if not browser_session.is_cdp_connected: