Skip to content

Warm the Start server graph on isolate first fetch - #1681

Merged
RhysSullivan merged 1 commit into
mainfrom
perf/warm-start-graph-first-fetch
Aug 19, 2026
Merged

Warm the Start server graph on isolate first fetch#1681
RhysSullivan merged 1 commit into
mainfrom
perf/warm-start-graph-first-fetch

Conversation

@RhysSullivan

Copy link
Copy Markdown
Collaborator

It is not load, and it is not the graph

Page latency was p50 19-49ms every day through 2026-08-16, then 2728ms the day after the 21:20 UTC deploy. The volume explanation behind #1628/#1634 does not survive the data:

total requests page p50
2026-08-11 5,427,583 40.98ms
2026-08-18 4,377,755 slow

More traffic on Aug 11, fast pages. So the reconnect storm was a coincident symptom, not the cause.

What actually changed

Where MCP work runs. The old hibernatable Agent bridge handed /mcp to the Durable Object almost immediately. The v2 stack authenticates and dispatches in the workermcp.auth.jwt_verify alone runs ~35k times per 6h there. That spins up far more worker isolates, and /mcp returns before fetchHandler, so none of those isolates ever loads the Start graph. Page requests land on them cold.

Measured, splitting the costs apart on a cold isolate:

p50
loadEntries graph import 3104ms
the request's own work 33ms
warm isolate, whole handler 9-104ms

The same production bundle in local workerd serves the same path in ~3ms, so this is a cold-isolate cost, not slow code.

Why re-land #1628

#1628 warmed on first fetch and worked. #1634 reverted it when memory kills jumped 500-900 → 3.7k-9.4k per 5min — but that landed during the Aug 17 storm, 11.67M requests in a day against a 2.6-4.3M baseline. Volume is back to baseline and exceededMemory is currently zero, so the condition that made warming expensive is gone.

I also tried a threshold variant (warm only after an isolate proves persistent, #1679) precisely to avoid that memory risk. It did not work — page requests are ~1 per isolate, so the threshold was rarely met before the request that needed it, and the warm import itself takes ~3s. Reverted in #1680.

START_GRAPH_WARM=false disables this without a deploy.

Verification

lint 0 errors, typecheck 44/44, apps/cloud vitest 280 passed. I will watch exceededMemory and page latency after deploy and flip the switch if kills move.

Page latency was p50 19-49ms daily up to 2026-08-16 and 2728ms the day
after the 21:20 deploy. Not load: 2026-08-11 served more total traffic
(5.43M vs 4.38M) with pages at p50 41ms, so the volume explanation does
not hold.

What changed is where MCP work runs. The old hibernatable Agent bridge
handed /mcp to the DO almost immediately; the v2 stack authenticates and
dispatches in the worker, spinning far more worker isolates. /mcp returns
before fetchHandler, so those isolates never load the Start graph, and
page requests land on them cold paying loadEntries: p50 3.1s, against 33ms
for the request's own work and 9-104ms warm.

Re-lands #1628. Its revert came during the Aug 17 storm (11.67M requests
against a 2.6-4.3M baseline); volume is back to baseline and
exceededMemory is currently zero. START_GRAPH_WARM=false disables it.
@RhysSullivan
RhysSullivan merged commit 29a0aea into main Aug 19, 2026
@RhysSullivan
RhysSullivan deleted the perf/warm-start-graph-first-fetch branch August 19, 2026 00:04
@github-actions

Copy link
Copy Markdown
Contributor

Cloudflare preview

Console https://executor-preview-pr-1681.executor-e2e.workers.dev
MCP https://executor-preview-pr-1681.executor-e2e.workers.dev/mcp
Deployed commit a81ccd7

Sign-in is Cloudflare Access (one-time PIN to an allowed email). The preview has its own database and encryption key; it is destroyed when this PR closes.

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