Skip to content

fix(app): keep slow git reads from filling the request queue - #47564

Merged
Hona merged 1 commit into
anomalyco:v2from
Hona:request-queue-lanes
Sep 6, 2026
Merged

fix(app): keep slow git reads from filling the request queue#47564
Hona merged 1 commit into
anomalyco:v2from
Hona:request-queue-lanes

Conversation

@Hona

@Hona Hona commented Sep 6, 2026

Copy link
Copy Markdown
Member

The request queue from #47441 is a plain FIFO with 4 slots. A Desktop netlog shows what sits in those slots during a session-tab mount:

Endpoint Server time
GET /api/vcs p50 1789 ms, max 2468 ms
GET /api/worktree p50 461 ms, max 2243 ms
GET /api/session/:id, /message, /permission, /form, catalogs p50 2–25 ms

A mount fires ~21 requests; two of them run git and can hold slots for over two seconds each. With several tabs mounting or a reconnect re-syncing directories, git reads take all 4 slots and the reads that actually paint the session sit behind them — which is exactly what server thrashing detected was logging (inflight: [GET /api/worktree…, GET /api/worktree…], queued: [GET /api/health]).

flowchart LR
  subgraph before [Before: FIFO x4]
    B[vcs · vcs · worktree · worktree] --> Q[queued: session, messages, permissions…]
  end
  subgraph after [After: slow share = 2 of 4]
    A1[vcs · vcs] --- A2[session · messages · …]
    A3[worktree · worktree] -.waits for a slow slot.-> A1
  end
Loading

Change — packages/app/src/runtime/server/request-queue.ts

  • slowRequestPaths = ["/api/vcs", "/api/worktree"] (prefix match, so /api/vcs/diff, /api/vcs/branches included); requestQueueSlowLimit = 2.
  • Slow requests may hold at most 2 of the 4 slots. Order stays FIFO otherwise: a slow request only yields its turn while the slow share is full, so nothing starves and fast reads never change order among themselves.
  • The wait list is scanned for the first eligible entry on each release instead of popping the head.
const canStart = (entry: Entry) => {
  if (inflight.size >= limit) return false
  if (!entry.slow) return true
  return [...inflight].filter((item) => item.slow).length < slowLimit
}
const release = (entry: Entry) => {
  inflight.delete(entry)
  const index = waiting.findIndex((item) => canStart(item.entry))
  if (index === -1) return
  waiting.splice(index, 1)[0]?.start()
}

Total concurrency is unchanged (4 + the event stream), so the Chromium per-origin limit reasoning in #47441 still holds.

Copilot AI lite review requested due to automatic review settings September 6, 2026 03:31
@Hona
Hona requested a review from Brendonovich as a code owner September 6, 2026 03:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@Hona
Hona force-pushed the request-queue-lanes branch from 09b60b5 to 0f37132 Compare September 6, 2026 05:14
@Hona
Hona merged commit 63a1074 into anomalyco:v2 Sep 6, 2026
8 checks passed
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.

2 participants