Deploy: warm immutable chunks BEFORE publishing the shell
Post-deploy slow-load fix (telemetry-confirmed): boot-slow beacons showed the shell arriving fast (33-79ms) but freshly-deployed chunks taking 3-5s, every event within ~6-8min of a deploy, the same chunks fast HITs later. Cause: the new shell went live pointing at chunk hashes not yet warm at the edge, so the first visitor fetched them cold from the residential origin (modulepreload fires them together → one unlucky "chunk warmer"). Reorder sync-static.sh: warm the immutable chunks at the edge BEFORE swapping in the new shell, so a published shell never references cold chunks. Shell + routes still warmed after publish. Pure deploy-script change — no runtime/SW changes. Warms the origin's nearest POP (covers local users + our own post-deploy testing); a distant POP still cold-fills once (inherent to a residential origin). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+37
-21
@@ -1,35 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
# Sync the built static site to the live root in an order that avoids deploy-race
|
||||
# blank screens. rsync isn't atomic, so a naïve `rsync --delete` can briefly serve
|
||||
# a NEW index.html that points at chunks not synced yet (→ failed load), or delete
|
||||
# old chunks an in-flight client still needs. Instead:
|
||||
# blank screens AND post-deploy slow loads. rsync isn't atomic, so a naïve
|
||||
# `rsync --delete` can briefly serve a NEW index.html that points at chunks not
|
||||
# synced yet (→ failed load), or delete old chunks an in-flight client still
|
||||
# needs. And even once synced, a new shell can point at chunks that aren't warm
|
||||
# at the CDN edge yet, so the unlucky first visitor fetches them cold from the
|
||||
# (residential) origin — the post-deploy slow-load window. So the order is:
|
||||
# 1. new hashed chunks first, and DON'T prune old ones (grace window)
|
||||
# 2. other static assets (version.json, env.js, icons…), pruning removed files
|
||||
# 3. the shell HTML — only once its chunks already exist
|
||||
# 4. the service worker last — a returning client adopts it only after the rest
|
||||
# 2. WARM those chunks at the edge BEFORE the shell goes live, so a new shell
|
||||
# never references cold chunks
|
||||
# 3. other static assets (version.json, icons…), pruning removed files
|
||||
# 4. the shell HTML — only once its chunks exist AND are warm
|
||||
# 5. the service worker last — a returning client adopts it only after the rest
|
||||
# 6. warm the shell + key routes after publish
|
||||
# Old immutable chunks are pruned after a grace window to bound disk growth.
|
||||
# NOTE: warming runs from this host, so it primes the Cloudflare POP nearest the
|
||||
# origin (great for local/nearby users + our own post-deploy testing); a distant
|
||||
# POP still cold-fills once on its first hit — inherent to a residential origin.
|
||||
set -euo pipefail
|
||||
src="$1"; site="$2"
|
||||
base="https://upbeatbytes.com"
|
||||
|
||||
# Warm a newline-separated list of paths (on stdin) through the public domain.
|
||||
# Best-effort: a warm miss must never fail the deploy.
|
||||
warm() { xargs -P 8 -I{} curl -fsS -o /dev/null --max-time 20 "$base{}" 2>/dev/null || true; }
|
||||
|
||||
# 1. New hashed chunks first (old ones kept — 14-day grace for in-flight clients).
|
||||
rsync -a "$src/_app/immutable/" "$site/_app/immutable/"
|
||||
|
||||
# 2. Warm the chunks BEFORE publishing the shell, so the new shell never points
|
||||
# at chunks still cold at the edge (the post-deploy slow-load cause).
|
||||
echo " warming new chunks (before publish)…"
|
||||
find "$site/_app/immutable" -type f \( -name '*.js' -o -name '*.css' \) -printf '/_app/immutable/%P\n' | warm
|
||||
|
||||
# 3. Other static assets (prune removed files), then 4. the shell, then 5. the SW.
|
||||
rsync -a --delete \
|
||||
--exclude='_app/immutable/***' --exclude='index.html' --exclude='service-worker.js' \
|
||||
"$src/" "$site/"
|
||||
rsync -a "$src/index.html" "$site/index.html"
|
||||
rsync -a "$src/service-worker.js" "$site/service-worker.js"
|
||||
find "$site/_app/immutable" -type f -mtime +14 -delete 2>/dev/null || true
|
||||
|
||||
# Warm the Cloudflare edge cache: fetch every immutable asset through the public
|
||||
# domain so the FIRST real visitor after a deploy gets cache HITs instead of slow
|
||||
# cold fetches from the (residential) origin — the post-deploy blank/slow-load cause.
|
||||
echo " warming edge cache…"
|
||||
base="https://upbeatbytes.com"
|
||||
{
|
||||
# every immutable chunk/asset (a superset of what index.html boots from)
|
||||
find "$site/_app/immutable" -type f \( -name '*.js' -o -name '*.css' \) -printf '/_app/immutable/%P\n'
|
||||
# shell + key routes + SW + version + static assets (primes CF↔origin even where
|
||||
# no-cache; caches the cacheable ones)
|
||||
printf '%s\n' / /play /account /admin /service-worker.js /_app/version.json \
|
||||
/manifest.webmanifest /words-5.json /words-6.json /logo.svg /favicon.svg \
|
||||
/icon-192.png /icon-512.png /fonts/inter-latin-wght-normal.woff2
|
||||
} | xargs -P 8 -I{} curl -fsS -o /dev/null --max-time 20 "$base{}" 2>/dev/null || true
|
||||
# 6. Warm the shell + key routes + remaining static now that they're published
|
||||
# (primes CF↔origin even where no-cache; caches the cacheable shell/routes).
|
||||
echo " warming shell + routes (after publish)…"
|
||||
printf '%s\n' / /play /account /admin /service-worker.js /_app/version.json \
|
||||
/manifest.webmanifest /words-5.json /words-6.json /logo.svg /favicon.svg \
|
||||
/icon-192.png /icon-512.png /fonts/inter-latin-wght-normal.woff2 | warm
|
||||
|
||||
# Bound disk growth: prune immutable chunks older than the grace window.
|
||||
find "$site/_app/immutable" -type f -mtime +14 -delete 2>/dev/null || true
|
||||
|
||||
Reference in New Issue
Block a user