Skip to content

fix: bound memory used by docs menu builds - #267

Merged
brookslybrand merged 1 commit into
mainfrom
fix/docs-menu-memory
Nov 6, 2026
Merged

brookslybrand merged 1 commit into
mainfrom
fix/docs-menu-memory

Conversation

@brookslybrand

Copy link
Copy Markdown
Contributor

What problem is this PR solving?

  • Fixes the reactrouter.com outage on 2026-11-05. Every production machine crashed repeatedly with JavaScript heap out of memory until Fly stopped restarting them, and docs pages returned Fastly 503s.
  • Menu builds now use much less memory, and a slow GitHub can no longer pile up work until the server crashes.

Note

Root cause: each menu build (one per docs version) downloads the full repo tarball and inflated all of it into one buffer. Crawler traffic was hitting docs for dozens of old versions (about 90 menu fetches in 100s), and GitHub was slow (about 4.5s per request), so many builds ran at the same time and filled the heap. Each crash emptied the in-memory caches, so after a restart every request missed the cache again. Restarting couldn't break that loop. Nothing had been deployed since Oct 22.

Changes:

  • Stream decompression in tarball.ts (zlib.createGunzip() → parseTar) instead of inflating the whole archive up front.
  • Cap concurrent menu builds at 4 in docs.ts. Extra builds wait in a queue, and lru-cache already merges concurrent fetches for the same key.
  • Timeouts on GitHub fetches: 30s for tarballs, 15s for raw doc content.

Local benchmark (20 concurrent builds of the main tarball × 8 rounds, after GC):

Peak RSS Retained ArrayBuffers
Before ~716 MB 61 MB
After ~281 MB 2 MB

In production the concurrency cap keeps actual usage well below this.

Warning

Temporary mitigation in place: production was scaled from 1 GB to 2 GB per machine (fly scale memory 2048 -a reactrouter) to stop the outage. Once this PR is deployed and stable, scale back with fly scale memory 1024 -a reactrouter.

🎩 Tophatting

  1. Deploy, then run fly logs -a reactrouter while browsing docs for several versions (e.g. /6.4.5/start/overview, /7.6.0/start/modes) → pages render, and you should see no FATAL ERROR ... heap out of memory.
  2. Run fly ssh console -a reactrouter -C 'sh -c "ps -o etime,rss,args | grep [n]ode"' after a few minutes → RSS stays well under 1 GB (it was 1.6–1.9 GB within ~3 minutes during the outage).

Generated by an AI agent on behalf of Brooks Lybrand. Model: Shopify Auto Best (shopify/auto-best); reasoning: unknown.

Stream tarball decompression instead of inflating the whole repo into
memory, cap concurrent menu builds at 4, and time out GitHub fetches.
Crawler traffic across many versions while GitHub was slow caused
unbounded concurrent builds that OOM-crashed every production machine.
@brookslybrand
brookslybrand merged commit bffe8dc into main Nov 6, 2026
5 checks passed
@brookslybrand
brookslybrand deleted the fix/docs-menu-memory branch November 6, 2026 14:43
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