Skip to content

Perf updates - #79

Merged
lucasdoell merged 6 commits into
mainfrom
staging
Jun 26, 2026
Merged

Perf updates#79
lucasdoell merged 6 commits into
mainfrom
staging

Conversation

@lucasdoell

Copy link
Copy Markdown
Member

No description provided.

The map page built and server-rendered all 11 tab contents on every load, so
each heavy tab (heatmap, replay, routes, events, compare, killfeed, charts,
overview) ran its own queries even when the user never opened it. Render only
the tab selected via ?tab= and stream it under Suspense; switching tabs is now a
shallow:false navigation. Fight-initiation is computed only when its tab is open.
ScrimPagination fired a second get-scrims request (limit=1, no filters) on every
load and team switch purely to tell an empty account apart from empty filter
results. The API now returns hasAnyScrims on the main response, computed with a
cheap findFirst only when the filtered page is empty, so the client needs a
single request instead of two.
The scrim overview page ran ~12 reads as a sequential await chain even though
most don't depend on each other. Group them into three parallel tiers: the
scrim/maps/user/feedback/visibility/flag reads, then the permission and context
reads that need the scrim and user, then the four heavy overview/positional/
initiation reads that were previously awaited one after another. Behavior is
unchanged; an early integer guard keeps malformed ids returning notFound before
the batch runs.
The overview ran its ten panel services with concurrency:"unbounded". The shared
base read is already deduped by an Effect cache, so firing everything at once
mostly just lets the secondary per-panel queries spike the connection pool and
stretch the tail past the 60s budget. Cap concurrency at 4.
The overview awaited all ten panel reads before sending any HTML, so the page's
first byte waited on the slowest service. Split it into three Suspense sections —
quick-stats ribbon, the insights + map-performance analysis block, and the
roster — each fetching only its own slice. The shared per-team base read is
deduped by the existing Effect cache, so the above-the-fold ribbon paints while
the heavier blocks stream in. Skeleton fragments are extracted so the route
loading boundary and the per-section fallbacks share them.
The hero stat-card percentile queries scan the whole PlayerStat table per hero
and were the app's biggest rows-read offender (~38M rows/day) despite being
global, slowly-changing population statistics. Wrap the two actively-used
baseline functions in unstable_cache with a 6h TTL so repeated stat-card reads
collapse to one scan per (hero, params) window. A shared hero-baselines tag is
attached so an upload hook can bust them eagerly later via revalidateTag.
@vercel

vercel Bot commented Jun 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
parsertime Ready Ready Preview, ✅ 2 resolved Jun 26, 2026 5:45am

@lucasdoell
lucasdoell merged commit da3e318 into main Jun 26, 2026
15 checks passed
@lucasdoell
lucasdoell deleted the staging branch June 26, 2026 05:45
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