From db2993ca92a773bc91c1280853fe0f96684453b7 Mon Sep 17 00:00:00 2001 From: ShawnPana Date: Tue, 10 Mar 2026 20:38:48 -0700 Subject: [PATCH] browser: skip throwaway WebSocket probes for wss:// cloud CDP profiles For cloud browser providers like Browser Use and Browserbase, each raw WebSocket health check provisions a new ephemeral browser session. Check the cached Playwright connection state instead, which reflects whether we actually have an active connection without side effects. --- src/browser/pw-session.ts | 7 +++++++ src/browser/server-context.availability.ts | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/browser/pw-session.ts b/src/browser/pw-session.ts index a7103c1174c..840499ccea5 100644 --- a/src/browser/pw-session.ts +++ b/src/browser/pw-session.ts @@ -119,6 +119,13 @@ const MAX_NETWORK_REQUESTS = 500; const cachedByCdpUrl = new Map(); const connectingByCdpUrl = new Map>(); +/** + * Returns true if there is an active cached Playwright connection for the given CDP URL. + */ +export function hasActivePlaywrightConnection(cdpUrl: string): boolean { + return cachedByCdpUrl.has(cdpUrl.replace(/\/$/, "")); +} + function normalizeCdpUrl(raw: string) { return raw.replace(/\/$/, ""); } diff --git a/src/browser/server-context.availability.ts b/src/browser/server-context.availability.ts index 3b00ff99dff..b8d617867ea 100644 --- a/src/browser/server-context.availability.ts +++ b/src/browser/server-context.availability.ts @@ -3,6 +3,7 @@ import { PROFILE_POST_RESTART_WS_TIMEOUT_MS, resolveCdpReachabilityTimeouts, } from "./cdp-timeouts.js"; +import { isWebSocketUrl } from "./cdp.helpers.js"; import { isChromeCdpReady, isChromeReachable, @@ -16,6 +17,7 @@ import { stopChromeExtensionRelayServer, } from "./extension-relay.js"; import { getBrowserProfileCapabilities } from "./profile-capabilities.js"; +import { hasActivePlaywrightConnection } from "./pw-session.js"; import { CDP_READY_AFTER_LAUNCH_MAX_TIMEOUT_MS, CDP_READY_AFTER_LAUNCH_MIN_TIMEOUT_MS, @@ -60,11 +62,20 @@ export function createProfileAvailability({ }); const isReachable = async (timeoutMs?: number) => { + // For direct WebSocket endpoints (e.g. Browser Use), each raw CDP health check + // opens a new WebSocket which may provision a new browser session. Check the + // cached Playwright connection instead — it reflects the actual connection state. + if (isWebSocketUrl(profile.cdpUrl)) { + return hasActivePlaywrightConnection(profile.cdpUrl); + } const { httpTimeoutMs, wsTimeoutMs } = resolveTimeouts(timeoutMs); return await isChromeCdpReady(profile.cdpUrl, httpTimeoutMs, wsTimeoutMs); }; const isHttpReachable = async (timeoutMs?: number) => { + if (isWebSocketUrl(profile.cdpUrl)) { + return hasActivePlaywrightConnection(profile.cdpUrl); + } const { httpTimeoutMs } = resolveTimeouts(timeoutMs); return await isChromeReachable(profile.cdpUrl, httpTimeoutMs); };