fix: per-profile browser caching to allow parallel connections
Changes global singleton cached/connecting variables to per-URL Maps. This allows different browser profiles (e.g., linkedin on port 18805, clawd on port 18800) to connect in parallel instead of blocking. Fixes #4289, #3605
This commit is contained in:
parent
da71eaebd2
commit
7f5e686742
@ -98,8 +98,9 @@ const MAX_CONSOLE_MESSAGES = 500;
|
|||||||
const MAX_PAGE_ERRORS = 200;
|
const MAX_PAGE_ERRORS = 200;
|
||||||
const MAX_NETWORK_REQUESTS = 500;
|
const MAX_NETWORK_REQUESTS = 500;
|
||||||
|
|
||||||
let cached: ConnectedBrowser | null = null;
|
// Per-profile caching to allow parallel connections to different Chrome instances
|
||||||
let connecting: Promise<ConnectedBrowser> | null = null;
|
const cachedByUrl = new Map<string, ConnectedBrowser>();
|
||||||
|
const connectingByUrl = new Map<string, Promise<ConnectedBrowser>>();
|
||||||
|
|
||||||
function normalizeCdpUrl(raw: string) {
|
function normalizeCdpUrl(raw: string) {
|
||||||
return raw.replace(/\/$/, "");
|
return raw.replace(/\/$/, "");
|
||||||
@ -281,8 +282,14 @@ function observeBrowser(browser: Browser) {
|
|||||||
|
|
||||||
async function connectBrowser(cdpUrl: string): Promise<ConnectedBrowser> {
|
async function connectBrowser(cdpUrl: string): Promise<ConnectedBrowser> {
|
||||||
const normalized = normalizeCdpUrl(cdpUrl);
|
const normalized = normalizeCdpUrl(cdpUrl);
|
||||||
if (cached?.cdpUrl === normalized) return cached;
|
|
||||||
if (connecting) return await connecting;
|
// Check if we already have a cached connection for this specific URL
|
||||||
|
const cached = cachedByUrl.get(normalized);
|
||||||
|
if (cached) return cached;
|
||||||
|
|
||||||
|
// Check if there's already a connection in progress for this specific URL
|
||||||
|
const existingConnecting = connectingByUrl.get(normalized);
|
||||||
|
if (existingConnecting) return await existingConnecting;
|
||||||
|
|
||||||
const connectWithRetry = async (): Promise<ConnectedBrowser> => {
|
const connectWithRetry = async (): Promise<ConnectedBrowser> => {
|
||||||
let lastErr: unknown;
|
let lastErr: unknown;
|
||||||
@ -294,10 +301,12 @@ async function connectBrowser(cdpUrl: string): Promise<ConnectedBrowser> {
|
|||||||
const headers = getHeadersWithAuth(endpoint);
|
const headers = getHeadersWithAuth(endpoint);
|
||||||
const browser = await chromium.connectOverCDP(endpoint, { timeout, headers });
|
const browser = await chromium.connectOverCDP(endpoint, { timeout, headers });
|
||||||
const connected: ConnectedBrowser = { browser, cdpUrl: normalized };
|
const connected: ConnectedBrowser = { browser, cdpUrl: normalized };
|
||||||
cached = connected;
|
cachedByUrl.set(normalized, connected);
|
||||||
observeBrowser(browser);
|
observeBrowser(browser);
|
||||||
browser.on("disconnected", () => {
|
browser.on("disconnected", () => {
|
||||||
if (cached?.browser === browser) cached = null;
|
if (cachedByUrl.get(normalized)?.browser === browser) {
|
||||||
|
cachedByUrl.delete(normalized);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
return connected;
|
return connected;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -313,11 +322,12 @@ async function connectBrowser(cdpUrl: string): Promise<ConnectedBrowser> {
|
|||||||
throw new Error(message);
|
throw new Error(message);
|
||||||
};
|
};
|
||||||
|
|
||||||
connecting = connectWithRetry().finally(() => {
|
const connectingPromise = connectWithRetry().finally(() => {
|
||||||
connecting = null;
|
connectingByUrl.delete(normalized);
|
||||||
});
|
});
|
||||||
|
connectingByUrl.set(normalized, connectingPromise);
|
||||||
|
|
||||||
return await connecting;
|
return await connectingPromise;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getAllPages(browser: Browser): Promise<Page[]> {
|
async function getAllPages(browser: Browser): Promise<Page[]> {
|
||||||
@ -450,10 +460,11 @@ export function refLocator(page: Page, ref: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function closePlaywrightBrowserConnection(): Promise<void> {
|
export async function closePlaywrightBrowserConnection(): Promise<void> {
|
||||||
const cur = cached;
|
// Close all cached browser connections
|
||||||
cached = null;
|
const connections = Array.from(cachedByUrl.values());
|
||||||
if (!cur) return;
|
cachedByUrl.clear();
|
||||||
await cur.browser.close().catch(() => {});
|
connectingByUrl.clear();
|
||||||
|
await Promise.all(connections.map((c) => c.browser.close().catch(() => {})));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user