@@ -83,7 +83,11 @@ rest: true # required for the @export-ed table REST endpoints
8383
8484 page :
8585 ttl : 86400000 # 24h — default cached-page TTL
86- minTtl : 21600000 # 6h — floor for sitemap-derived TTLs
86+ minTtl : 21600000 # 6h — floor for sitemap-derived TTLs. Also floors the RENDER INTERVAL a
87+ # sitemap's `changefreq` produces, and therefore the width of the
88+ # initial-render jitter: `changefreq: hourly` becomes a 6h cadence
89+ # spread over 6h, i.e. 4x the sustained render load of `daily`.
90+ # Raise this to slow a fleet down; it trades page freshness for load.
8791 swrTtl : 10800000 # 3h — stale-while-revalidate window
8892
8993 render :
@@ -241,6 +245,33 @@ A forwarded-mode config that compiles to **zero** prerender routes is reported a
241245(`/prerender_admin` surfaces it) : nothing is prerendered in that state, and it is what a single
242246typo produces, since invalid entries are dropped one at a time.
243247
248+ # ## How bulk sitemap population is staggered
249+
250+ Populating a large sitemap must not queue every URL at once. A new target's first render is
251+ therefore `now + (hash(url) % renderInterval)`, floored to the minute — a uniform spread over the
252+ interval, so the fleet sees a flat stream rather than a herd. Because `processJobResult`
253+ reschedules from **render completion** (`currentMinuteMs() + interval`) rather than a fixed
254+ time-of-day, that spread is preserved cycle over cycle and self-paces to fleet throughput.
255+
256+ Three properties are worth knowing before a bulk upload :
257+
258+ - **The stagger window is the target's own `renderInterval`, not a fixed 24h.** For a sitemap
259+ target that comes from `changefreq`, floored at `page.minTtl` — so `always`/`hourly` spread over
260+ ` minTtl` (6h by default) and re-render that often, i.e. 4× the sustained load of `daily`. A
261+ sitemap's `changefreq` is the single biggest determinant of steady-state render load, and it
262+ comes from the sitemap XML, not from this config. Check it before uploading.
263+ - **A URL's device variants share one slot.** The offset is seeded off the URL half of the cache
264+ key, so `…|desktop` and `…|mobile` come due together, sort adjacently in claim order, and get
265+ rendered back-to-back by one worker off a warm origin. It also keeps the cached copies of one
266+ page the same age — seeded off the full key they drifted up to a whole interval apart, so a
267+ content change could appear on one device and not the other for hours.
268+ - **`revalidate: true` bypasses the stagger entirely**, setting every entry due in the same
269+ minute. That is its purpose (forcing a backfill), but it is not how to warm a large sitemap for
270+ the first time — omit it and let the jitter place the URLs.
271+
272+ There is no separate "warm-up" pacing knob, and none is needed : the initial spread is exactly the
273+ steady-state cadence, so a fleet that can sustain the ongoing load can absorb the warm.
274+
244275# ## Staging passthrough
245276
246277To verify an origin against a staging edge (e.g. a CDN's staging network) _through_ the
@@ -336,7 +367,11 @@ this plugin's resources all set `loadAsInstance = false`.
336367- **Overview** — per-node queue status with staleness, table counts, the due-now backlog, and
337368 a next-24h histogram of `nextRenderTime`. That histogram is the quickest way to tell a
338369 healthy jittered spread from a render herd : a flat distribution means the initial-render
339- jitter is working, a single tall bar means everything comes due at once.
370+ jitter is working, a single tall bar means everything comes due at once. Note the histogram
371+ is capped at `management.scanCap` rows and reports `truncated` — at a large registry read the
372+ shape, not the counts. The due-now backlog is the capacity signal : jitter flattens the
373+ arrival curve but cannot lower it, so a backlog that climbs and never returns to zero means
374+ sustained demand (`Σ targets ÷ renderInterval`) exceeds fleet throughput.
340375- **URL explainer** — paste a URL and see the ingress route that matched, the query allowlist
341376 it selected, the canonical URL, the resulting cache key, and the live
342377 ` RenderTarget` /`RenderSchedule`/`PrerenderedPage`/`NonIndexable` rows under it. It also
0 commit comments