mirror of
https://github.com/browser-use/browser-use
synced 2026-04-22 17:45:09 +02:00
Fix reconnection wait timeout to cover full auto-reconnect window
The circuit breaker and agent error handler were using a hardcoded 20s timeout, but the worst-case auto-reconnect window is ~48s (3 attempts * 15s + 7s delays). Handlers would raise ConnectionError while reconnection was still in progress. Now both use BrowserSession.RECONNECT_WAIT_TIMEOUT (54s) derived from the actual reconnect parameters.
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user