Skip to content

fix: cap concurrency in detectOpenDevToolsWindows to avoid CDP fan-out on many-tab profiles#2274

Open
mvanhorn wants to merge 1 commit into
ChromeDevTools:mainfrom
mvanhorn:fix/1921-cap-devtools-detect-concurrency
Open

fix: cap concurrency in detectOpenDevToolsWindows to avoid CDP fan-out on many-tab profiles#2274
mvanhorn wants to merge 1 commit into
ChromeDevTools:mainfrom
mvanhorn:fix/1921-cap-devtools-detect-concurrency

Conversation

@mvanhorn

@mvanhorn mvanhorn commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Caps the concurrency of the DevTools-window detection pass so it no longer issues one simultaneous CDP call per open tab.

Why

detectOpenDevToolsWindows() in src/McpContext.ts fanned out an unbounded Promise.all(pages.map(...)) over every open page, so each tab issued its own hasDevTools() / openDevTools() CDP round-trip at the same time. This method runs on init and again on every response that carries includePages, so a single tool call could put one concurrent CDP call in flight per tab.

On a profile with a very large number of tabs this becomes hundreds to thousands of simultaneous CDP calls on the first tool call, which is one of the paths that can make the browser hang or crash (Refs #1921).

Change

Bound the fan-out with a small fixed-size worker pool. A new mapWithConcurrency(items, limit, worker) helper runs at most limit workers at once (default cap 10, DEVTOOLS_DETECTION_CONCURRENCY), each pulling the next page from a shared index. detectOpenDevToolsWindows() now walks the pages through this helper with the exact same per-page body it had before.

  • Profiles at or below the cap behave identically to before.
  • The existing per-page try/catch fallback for pre-144.0.7559.59 Chrome/Electron (where the DevTools command throws) is preserved, and one page failing does not abort detection for the rest.

This is deliberately narrow: it only caps the concurrency of the existing detection pass and does not change what gets detected or attached. It is one piece of the broader many-tab hardening tracked in #1921, not a full fix for it.

Testing

Added unit tests for mapWithConcurrency in tests/McpContext.test.ts covering:

  • every item is processed exactly once below the limit;
  • the observed maximum in-flight worker count never exceeds the limit while all items still complete (50 items, limit 3);
  • a rejecting worker does not prevent the remaining items from being processed.

npm run check-format, npm run build, and npm test all pass locally.

detectOpenDevToolsWindows ran an unbounded Promise.all over every open
page, issuing one hasDevTools()/openDevTools() CDP round-trip per tab
simultaneously. On profiles with a large number of tabs this fans out
hundreds to thousands of concurrent CDP calls on the first tool call,
which can hang or crash the browser.

Bound the fan-out with a small fixed-size worker pool
(mapWithConcurrency, limit 10) so at most a constant number of CDP
round-trips are in flight at once. Behavior is unchanged for profiles
at or below the cap, and the existing per-page try/catch fallback for
pre-144 Chrome/Electron is preserved.

Refs ChromeDevTools#1921
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant