Skip to content

fix(index): stop blocking page render on the modarchive RSS feed - #209

Merged
indigo423 merged 2 commits into
mainfrom
fix/index-ttfb-latest-id
Oct 8, 2026
Merged

indigo423 merged 2 commits into
mainfrom
fix/index-ttfb-latest-id

Conversation

@indigo423

Copy link
Copy Markdown
Collaborator

Closes #208

What

The start page's getServerSideProps awaited https://modarchive.org/rss.php?request=uploads on every request. It only needed the newest module id, which is the upper bound for random picks. That feed takes 2.5 to 4 s to answer, so every visitor waited that long for the first byte.

  • New lib/modarchive/latest-id.ts: getLatestId(fallback) returns the cached id right away, or the fallback before the first fetch lands. A value older than one hour triggers one background refresh. The refresh times out after 10 s. A failed fetch keeps the last good value.
  • pages/index.tsx calls getLatestId(RANDOM_MAX) instead of the blocking fetch. The file also gets its missing SPDX header.
  • lib/modarchive/latest-id.test.ts covers the fallback, caching, single in-flight refresh, failure, and TTL expiry.

Trade-off

For the first seconds after a server restart, pages get RANDOM_MAX (190580). The old code already used that value whenever the fetch failed. During that window random picks can't land on the newest uploads.

Verification

  • make verify passes (lint, typecheck, unit tests, audit, build).
  • Local next start, four requests to / 3 s apart:
ttfb 0.045s  "latestId":190580   fallback, refresh in flight
ttfb 0.004s  "latestId":190580
ttfb 0.004s  "latestId":190580
ttfb 0.004s  "latestId":215286   real value from modarchive.org

Production before this change: 2.65 s, 2.73 s, 4.05 s TTFB.

馃 Generated with Claude Code

https://claude.ai/code/session_01GwowRkcBNzHsDGBXywedzR

indigo423 and others added 2 commits October 8, 2026 13:07
getServerSideProps awaited modarchive.org/rss.php on every request to
find the newest module id. The feed takes 2.5 to 4 s to answer, so the
start page TTFB was about 3 s for every visitor.

Move the lookup into lib/modarchive/latest-id.ts. getLatestId() returns
the cached id, or RANDOM_MAX before the first fetch lands, and starts
one background refresh when the value is older than an hour. A failed
or timed-out (10 s) fetch keeps the previous value.

Local production build: TTFB 45 ms on the first request, 4 ms after.

Closes #208

Assisted-by: ClaudeCode:claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwowRkcBNzHsDGBXywedzR
Signed-off-by: Ronny Trommer <ronny@no42.org>
- Clear the in-flight promise via .finally() in getLatestId, so a
  synchronous throw inside fetch can no longer leave a settled promise
  in `refreshing` and block every later refresh.
- Retry a failed fetch after one minute instead of a full hour, so a
  cold-start failure does not pin visitors to RANDOM_MAX.
- Reuse fetchHtml (project User-Agent, throws on non-2xx) with a new
  optional AbortSignal parameter instead of a bare fetch.
- Document the long-lived server process assumption.
- Tests for non-2xx, retry after failure, and synchronous throw.

Refs #208

Assisted-by: ClaudeCode:claude-opus-5-5
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GwowRkcBNzHsDGBXywedzR
Signed-off-by: Ronny Trommer <ronny@no42.org>
@indigo423
indigo423 merged commit 00217bc into main Oct 8, 2026
4 checks passed
@indigo423
indigo423 deleted the fix/index-ttfb-latest-id branch October 8, 2026 20:32
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.

[Start page] Page stays blank for about 3 s on every load

1 participant