perf(analyze-site): parallelize script execution for ~1-2s speedup#18
perf(analyze-site): parallelize script execution for ~1-2s speedup#18Shawn1993 wants to merge 1 commit intoopentabs-dev:mainfrom
Conversation
BREAKING: None (behavior unchanged) Before: 11 sequential executeInTab calls + 3 sequential dispatchToExtension calls After: All run in parallel using Promise.allSettled Expected improvement: - ~1-2s faster per analyzeSite call - Reduces 14 round-trips to 2 parallel batches The rate limit concern mentioned in the old comments (10 calls/sec) is not applicable here since all scripts complete within ~50ms in page context. Promise.allSettled preserves the partial-results behavior from the original try-catch blocks.
opentabs-dev
left a comment
There was a problem hiding this comment.
Review — PR #18
Clean refactor. Promise.allSettled is the right choice here — the scripts read independent DOM state (no ordering dependency), and partial-results behavior is preserved via the fulfilled/rejected checks.
One concern
The original code had a comment about a rate limit ("max 10 browser.executeScript calls per second"). The PR dismisses this as not a concern since scripts complete in ~50ms. But the rate limit is about calls initiated per second, not execution time — 11 simultaneous dispatches do land at the same instant. I believe the rate limit concern was overly cautious in the original code (the extension processes dispatches concurrently with no real throttle), but worth calling out that the dismissal reasoning in the comment is slightly off.
Overlap with PR #19
This PR's entire diff is duplicated in PR #19 (feat/batch-get-tab-content). These two PRs will conflict. Suggest merging this one first, then rebasing #19 on top.
Approving — the change is correct and the code is cleaner.
opentabs-dev
left a comment
There was a problem hiding this comment.
Revoking earlier approval — needs deeper analysis on concurrency safety.
Rate limit: passes, but the original comment was wrong
The extension's rate limiter allows 15 browser.executeScript calls per second (not 10 as the original code comment claimed). 11 parallel calls fits under 15, so the rate limit itself is not the issue.
Real concern: 11 concurrent file-based script injections on the same tab
Each executeInTab call does three things:
writeExecFile— writes a unique file to disk (UUID-based, no collision)dispatchToExtension('browser.executeScript', { tabId, execFile })— sends to extension- Extension calls
chrome.scripting.executeScript({ files: [...], world: 'MAIN' })on the target tab
With 11 parallel calls, Chrome's chrome.scripting.executeScript must handle 11 concurrent file injections into the same tab. The result isolation is safe (each uses __execResult_<uuid>), but I'd like to verify:
- Does Chrome serialize
chrome.scripting.executeScriptcalls to the same tab, or can they truly interleave? - Could 11 simultaneous MAIN world injections cause any Chrome internal contention or ordering issues?
- The follow-up
funcinjection that reads back the result — could it race with another script's result write?
The PR comment dismisses the rate limit concern ("all 11 scripts complete within ~50ms each") but that reasoning conflates execution time with dispatch concurrency. The question is not how fast each script runs, but whether 11 concurrent chrome.scripting.executeScript calls to the same tab are well-defined behavior.
Also: 11 concurrent writeExecFile calls
Each writes to the extension's adapters/ directory. The writes use unique filenames so they won't collide, but 11 near-simultaneous file writes + 11 near-simultaneous file deletes could create I/O pressure on the extension directory. Unlikely to be a problem in practice, but worth confirming.
Recommendation
The parallelization is likely correct and safe, but the PR should demonstrate this with evidence (e.g., a test that runs 11 concurrent executeInTab calls and verifies all results), not just assert it in a comment. The original sequential code was conservative for a reason — the PR should prove the concern was unfounded, not just dismiss it.
opentabs-dev
left a comment
There was a problem hiding this comment.
Deep Review — PR #18: Parallelize analyze-site script execution
Verdict: The parallelization is safe. Approving with one minor fix needed.
I traced the full dispatch path and verified each concurrency concern:
1. chrome.scripting.executeScript concurrent calls to the same tab — SAFE
JavaScript's single-threaded execution model in the tab's renderer process guarantees run-to-completion for each injected IIFE. Chrome queues concurrent executeScript calls at the renderer level. The extension's handleBrowserExecuteScript in message-router.ts places no serialization guards — each call fires immediately.
2. Result read-back race — SAFE by design
Each executeInTab uses crypto.randomUUID() to namespace results (__execResult_<uuid>) in adapter-files.ts:160-209. The polling function reads only the matching UUID key. 11 concurrent executions write to 11 different keys — zero cross-contamination. The code comment at line 171 explicitly states: "so concurrent executions on the same tab do not collide."
3. MAX_CONCURRENT_DISPATCHES_PER_PLUGIN = 5 — Does NOT apply
This limit in mcp-tool-dispatch.ts:35 only gates handlePluginToolCall. Browser tools go through handleBrowserToolCall which has no concurrency limiter. executeInTab calls dispatchToExtension directly, bypassing the plugin dispatch path entirely.
4. Extension rate limiter — SAFE (but the PR comment is wrong)
rate-limiter.ts:21: browser.executeScript allows 15/sec, not 10. 11 concurrent calls is under 15. The polling for result readback uses direct Chrome API calls, not WebSocket messages, so they don't count against the rate limiter.
5. Filesystem — SAFE
UUID-based filenames prevent collisions. atomicWrite uses temp-file + rename. mkdir({ recursive: true }) is idempotent.
6. WebSocket correlation — SAFE
dispatchToExtension uses unique request IDs from getNextRequestId(). 11 concurrent dispatches produce 11 independent IDs tracked in state.pendingDispatches.
One fix needed
The PR's comment on line 839-841 says:
The extension's rate limit (10 calls/sec) is not a concern here
The actual limit is 15/sec (rate-limiter.ts:21). Fix the comment to say 15 (or just remove the specific number).
Summary
The parallelization is correct. UUID namespacing, single-threaded JS execution, and request ID correlation all ensure safety. Fix the rate limit number in the comment.
There was a problem hiding this comment.
Review Update
The parallelization is verified safe (see previous deep review). One remaining fix needed:
Fix the rate limit number in the comment
The comment says the extension's rate limit is 10 calls/sec. The actual limit is 15/sec (rate-limiter.ts:21). Fix the comment to say 15 or remove the specific number.
That's the only remaining blocker. Once fixed, this is ready to merge.
Summary
Parallelizes the sequential
executeInTabanddispatchToExtensioncalls inanalyzeSite, reducing tool latency by approximately 1-2 seconds per call.Changes
executeInTabcalls → 1 parallel batch usingPromise.allSettleddispatchToExtensioncalls → 1 parallel batchBefore
After
Why this is safe
Promise.allSettledpreserves the partial-results behavior from the original try-catch blocksPerformance improvement