fix: recover zombie browser contexts during tab creation (#5416)

Bound new-page creation with a configurable 10-second deadline, replace only the affected user context on timeout/dead-context failures, and retry once.

Co-authored-by: Pradeep Elankumaran <pradeep@askjo.ai>
This commit is contained in:
Love-JourneY
2026-07-19 22:44:17 -07:00
committed by GitHub
co-authored by Pradeep Elankumaran
parent f4c219ee71
commit f15148b05d
7 changed files with 196 additions and 4 deletions
+23 -2
View File
@@ -33,6 +33,7 @@ import {
import { actionFromReq, classifyError } from './lib/request-utils.js';
import { cleanupOrphanedTempFiles, cleanupStaleFirefoxProfiles } from './lib/tmp-cleanup.js';
import { coalesceInflight } from './lib/inflight.js';
import { createPageWithSessionRecovery } from './lib/new-page-recovery.js';
import { createReporter, createTabHealthTracker, collectResourceSnapshot, classifyProxyError, browserProcessTreeRssMb, browserProcessNameRssMb } from './lib/reporter.js';
import { mountDocs } from './lib/openapi.js';
import { initSentry, captureException as sentryCaptureException, setupExpressErrorHandler as setupSentryErrorHandler, flush as sentryFlush } from './lib/sentry.js';
@@ -483,6 +484,7 @@ const MAX_SESSIONS = CONFIG.maxSessions;
const MAX_TABS_PER_SESSION = CONFIG.maxTabsPerSession;
const MAX_TABS_GLOBAL = CONFIG.maxTabsGlobal;
const HANDLER_TIMEOUT_MS = CONFIG.handlerTimeoutMs;
const NEW_PAGE_TIMEOUT_MS = CONFIG.newPageTimeoutMs;
const MAX_CONCURRENT_PER_USER = CONFIG.maxConcurrentPerUser;
const PAGE_CLOSE_TIMEOUT_MS = 5000;
const NAVIGATE_TIMEOUT_MS = CONFIG.navigateTimeoutMs;
@@ -1313,6 +1315,23 @@ async function getSession(userId, { trace = false } = {}) {
return session;
}
async function createPageWithRecoveryForUser(userId, session, { trace = false } = {}) {
const key = normalizeUserId(userId);
return createPageWithSessionRecovery({
userId: key,
session,
trace,
timeoutMs: NEW_PAGE_TIMEOUT_MS,
withTimeout,
isTimeoutError,
isDeadContextError,
currentSession: () => sessions.get(key),
destroySession,
getSession,
log,
});
}
function getTabGroup(session, listItemId) {
let group = session.tabGroups.get(listItemId);
if (!group) {
@@ -2726,9 +2745,11 @@ app.post('/tabs', async (req, res) => {
}
}
const createdPage = await createPageWithRecoveryForUser(userId, session, { trace: !!trace });
session = createdPage.session;
const page = createdPage.page;
const group = getTabGroup(session, resolvedSessionKey);
const page = await session.context.newPage();
const tabId = fly.makeTabId();
let tabState = createTabState(page);
attachDownloadListener(tabState, tabId, log, pluginEvents, userId);