From 3cbfe41713f7150030bab12e528a0d81d3a81b76 Mon Sep 17 00:00:00 2001 From: ssavutu Date: Tue, 1 Sep 2026 18:54:37 -0400 Subject: [PATCH] Stop the service-worker check reading Cloudflare's cached 404 The deploy for #103 failed on the service-worker check with six 404s in a row, while the worker was on disk with the build's timestamp and both the app and nginx served it 200. Cloudflare caches 404s for about three minutes, and deploy-scalene has a window where the build has replaced dist/client but the app has not restarted -- a request landing there falls through to the [sectionSlug] catch-all as an HTML 404. Cloudflare cached that, and the check read the cached copy for its whole retry window. Give the URL a unique query string per run: a distinct cache key always reaches the origin, so the check asserts what was deployed rather than what Cloudflare happens to be holding. Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01Tx3ywgRQLzzrZWNcSdtTpr --- .github/workflows/deploy-production.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deploy-production.yml b/.github/workflows/deploy-production.yml index 24541ab..585df77 100644 --- a/.github/workflows/deploy-production.yml +++ b/.github/workflows/deploy-production.yml @@ -65,6 +65,13 @@ jobs: # /sw.js is a root path, so a missing worker does not fail loudly: the # request falls through to the [sectionSlug] catch-all and comes back as # an HTML error page. Assert the content type, not just the status. + # + # The URL carries a cache buster because Cloudflare caches 404s for about + # three minutes: a request that lands in the window where the build has + # replaced dist/client but the app has not restarted gets that HTML 404 + # cached, and this step then reads the cached copy for its whole retry + # window while the origin is serving the worker perfectly well. A unique + # query string is a distinct cache key, so this always asks the origin. - name: Verify service worker is served run: | content_type=$( @@ -79,7 +86,7 @@ jobs: --retry-all-errors \ --output /dev/null \ --write-out '%{content_type}' \ - https://www.thetriangle.org/sw.js + "https://www.thetriangle.org/sw.js?deploy=${GITHUB_RUN_ID}-${GITHUB_RUN_ATTEMPT}" ) case "$content_type" in *javascript*)