From a196e53cfdef5e12e56c4a786ce6307057155e65 Mon Sep 17 00:00:00 2001 From: Anthony Ettinger Date: Sun, 30 Aug 2026 03:04:24 +0000 Subject: [PATCH] site: surface a new release within a minute, not an hour MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit v0.1.8 was published, built and downloadable while diskpush.com/download still offered v0.1.7 — the page renders per request, but the fetch under it was cached for an hour, so re-rendering only ever re-rendered stale data. Three caches gated the same fact and all three were an hour: the GitHub fetch in latestRelease(), the /api/releases/latest route's own revalidate, and the s-maxage it sends downstream. Lowering one and not the others would have left the page and the API it exposes disagreeing about what the latest release is. Next revalidates lazily — on the first request after the window lapses, not on a timer — so 60s is a ceiling of 60 GitHub calls an hour, and the real number tracks traffic rather than the clock. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01Y5jnkZKX4AdPgBMzMosxE7 --- apps/web/app/api/releases/latest/route.ts | 4 ++-- apps/web/app/download/page.tsx | 11 +++++++++-- apps/web/lib/releases.ts | 2 +- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/apps/web/app/api/releases/latest/route.ts b/apps/web/app/api/releases/latest/route.ts index 793fbf3..d46a012 100644 --- a/apps/web/app/api/releases/latest/route.ts +++ b/apps/web/app/api/releases/latest/route.ts @@ -1,7 +1,7 @@ import { NextResponse } from 'next/server' import { latestRelease } from '@/lib/releases' -export const revalidate = 3600 +export const revalidate = 60 /** * Normalised latest-release metadata, so the download UI never has to know @@ -15,5 +15,5 @@ export async function GET() { { headers: { 'Cache-Control': 'public, s-maxage=600' } }, ) } - return NextResponse.json(release, { headers: { 'Cache-Control': 'public, s-maxage=3600' } }) + return NextResponse.json(release, { headers: { 'Cache-Control': 'public, s-maxage=60' } }) } diff --git a/apps/web/app/download/page.tsx b/apps/web/app/download/page.tsx index 6c97d1a..a62fd8a 100644 --- a/apps/web/app/download/page.tsx +++ b/apps/web/app/download/page.tsx @@ -20,8 +20,15 @@ export const metadata: Metadata = { // old while `install.sh`, which asks the GitHub API at run time, was handing // out the current one. // -// The fetch in latestRelease() keeps its own hourly cache, so per-request -// rendering costs a render and not a GitHub call. +// The fetch in latestRelease() keeps its own cache, so per-request rendering +// costs a render and not a GitHub call. That cache is 60s rather than an hour: +// a release is the one thing a visitor here is looking for, and v0.1.8 was +// published and downloadable while this page still offered v0.1.7. Next +// revalidates lazily -- on the first request after the window lapses, not on a +// timer -- so the ceiling is 60 GitHub calls an hour and the real number +// tracks traffic. Worth knowing before lowering it further: unauthenticated +// GitHub allows exactly 60 an hour per IP, and latestRelease() answers null on +// a refusal, which renders as no release at all. export const dynamic = 'force-dynamic' export default async function DownloadPage() { diff --git a/apps/web/lib/releases.ts b/apps/web/lib/releases.ts index 68b61d6..99a4109 100644 --- a/apps/web/lib/releases.ts +++ b/apps/web/lib/releases.ts @@ -37,7 +37,7 @@ export async function latestRelease(): Promise { try { const response = await fetch(ENDPOINT, { headers: { Accept: 'application/vnd.github+json' }, - next: { revalidate: 3600 }, + next: { revalidate: 60 }, }) // A repository with no tagged release yet answers 404. That is a normal // state before launch, not an error worth surfacing to a visitor.