web: adopt Cache Components, Partial Prefetching and ensureStatic
web / ci (push) Successful in 2m2s
web / ci (push) Successful in 2m2s
This commit is contained in:
70 files changed
+1285
-316
No files matched your search
@@ -0,0 +1,88 @@
|
||||
import { osloDay } from "@/lib/date";
|
||||
import {
|
||||
purgeOwnCache,
|
||||
setInternalRevalidateSecret,
|
||||
} from "@/lib/internalRevalidate";
|
||||
import {
|
||||
CMS_CACHE_TAG,
|
||||
TODAY_CACHE_TAG,
|
||||
secondsUntilOsloMidnight,
|
||||
} from "@/lib/revalidation";
|
||||
|
||||
// How often the clock is checked. Timers alone can't be trusted to fire at
|
||||
// midnight: they stand still while a host or VM is paused
|
||||
const CHECK_INTERVAL_MS = 30_000;
|
||||
// Until the first purge has gone through; the server isn't listening yet
|
||||
// when register() runs
|
||||
const STARTUP_RETRY_MS = 1_000;
|
||||
|
||||
function keepCacheCurrent() {
|
||||
// the Oslo day the cache was last purged for; undefined until the startup
|
||||
// purge has gone through
|
||||
let purgedDay: string | undefined;
|
||||
let repeatTodayPurge = false;
|
||||
let failures = 0;
|
||||
|
||||
async function check() {
|
||||
const day = osloDay();
|
||||
let error: string | null = null;
|
||||
|
||||
if (purgedDay === undefined) {
|
||||
// Pages prerendered by the build, or left on disk by an earlier run,
|
||||
// may predate CMS edits and midnights this process never saw
|
||||
error =
|
||||
(await purgeOwnCache(CMS_CACHE_TAG)) ??
|
||||
(await purgeOwnCache(TODAY_CACHE_TAG));
|
||||
if (!error) purgedDay = day;
|
||||
} else if (day !== purgedDay) {
|
||||
error = await purgeOwnCache(TODAY_CACHE_TAG);
|
||||
if (!error) {
|
||||
purgedDay = day;
|
||||
repeatTodayPurge = true;
|
||||
}
|
||||
} else if (repeatTodayPurge) {
|
||||
// Next stamps a page when its render finishes, so a page that was
|
||||
// being rendered across the purge looks newer than it and survives.
|
||||
// A second purge one interval later catches those
|
||||
error = await purgeOwnCache(TODAY_CACHE_TAG);
|
||||
if (!error) repeatTodayPurge = false;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
failures += 1;
|
||||
// at startup, connection errors are expected for the first moments
|
||||
if (failures === 1 ? purgedDay !== undefined : failures % 60 === 0) {
|
||||
console.error(`Purging the page cache keeps failing: ${error}`);
|
||||
}
|
||||
} else {
|
||||
failures = 0;
|
||||
}
|
||||
schedule();
|
||||
}
|
||||
|
||||
function schedule() {
|
||||
const delay =
|
||||
purgedDay === undefined
|
||||
? STARTUP_RETRY_MS
|
||||
: // one second past midnight, so the purge can't land on the old day
|
||||
Math.min(CHECK_INTERVAL_MS, (secondsUntilOsloMidnight() + 1) * 1000);
|
||||
setTimeout(check, delay).unref();
|
||||
}
|
||||
|
||||
void check();
|
||||
}
|
||||
|
||||
export function register() {
|
||||
// only in the running production server: not during `next build`, in
|
||||
// `next dev` (nothing is kept between requests there) or on the edge
|
||||
if (
|
||||
process.env.NEXT_RUNTIME !== "nodejs" ||
|
||||
process.env.NODE_ENV !== "production" ||
|
||||
process.env.NEXT_PHASE === "phase-production-build"
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
setInternalRevalidateSecret(crypto.randomUUID());
|
||||
keepCacheCurrent();
|
||||
}
|
||||
Reference in new issue
Block a user