Cache fixing by unit path invalidation instead of individual file listing#1464
Cache fixing by unit path invalidation instead of individual file listing#1464abcampo-iry wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates the deploy workflow’s cache invalidation strategy by switching Cloudflare purging from a hard-coded list of specific asset URLs to purging by deployed path prefixes, and ensures latest_version is uploaded with revalidation-friendly caching headers.
Changes:
- Upload
latest_versionto S3 withCache-Control: no-cache(for tag builds). - Build a Cloudflare purge payload dynamically using path prefixes derived from the computed deploy URLs.
- Replace the previous single-file Cloudflare purge request with the generated prefix-based purge request.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| latest_version_url="" | ||
| if [ "${{ github.ref_type }}" = "tag" ]; then | ||
| latest_version_url="${{ inputs.base_url }}/latest_version" | ||
| fi | ||
|
|
||
| purge_payload="$( | ||
| jq -cn \ | ||
| --arg public_url "${{ needs.setup-environment.outputs.public_url }}" \ | ||
| --arg html_renderer_url "${{ needs.setup-environment.outputs.html_renderer_url }}" \ | ||
| --arg latest_version_url "$latest_version_url" \ | ||
| '[($public_url + "/"), ($html_renderer_url + "/"), $latest_version_url] | ||
| | map(select(length > 0)) | ||
| | map(sub("^https?://"; "")) | ||
| | map(gsub("/+"; "/")) | ||
| | unique | ||
| | {prefixes: .}' | ||
| )" | ||
|
|
||
| echo "Purging Cloudflare cache prefixes:" | ||
| jq -r '.prefixes[] | " - \(.)"' <<<"$purge_payload" | ||
|
|
||
| response="$( | ||
| curl -sS --fail-with-body -X POST "https://api.cloudflare.com/client/v4/zones/${CLOUDFLARE_ZONE_ID}/purge_cache" \ | ||
| -H "Authorization: Bearer ${CLOUDFLARE_API_TOKEN}" \ | ||
| -H "Content-Type: application/json" \ | ||
| --data '{"files":["${{ needs.setup-environment.outputs.public_url }}/web-component.html", "${{ needs.setup-environment.outputs.public_url }}/web-component.js", "${{ needs.setup-environment.outputs.public_url }}/scratch.html", "${{ needs.setup-environment.outputs.public_url }}/scratch.js", "${{ inputs.base_url }}/latest_version", "${{ needs.setup-environment.outputs.html_renderer_url}}/html-renderer.html", "${{ needs.setup-environment.outputs.html_renderer_url}}/html-renderer.js"]}' | ||
| --data "$purge_payload" |
There was a problem hiding this comment.
I do find this code harder to understand now because it is doing a lot now and the has all the actions interpolation within it. Do you think extracting it to a bash or Ruby script could make it easier to follow? Or is there any other way to simplify it?
|
Thanks for the explanation and links to the doc. I've added a comment. I also wondered if we set a no cache for |
Closes https://github.com/RaspberryPiFoundation/digital-editor-issues/issues/1371
What changed
This PR changes the deploy workflow to purge Cloudflare by deployed path prefix instead of by a hard-coded list of individual files.
A staging deploy now purges:
{ "prefixes": [ "staging-editor-static.raspberrypi.org/branches/main/" ] }while before:
{ "files": [ "https://staging-editor-static.raspberrypi.org/branches/main/web-component.html", "https://staging-editor-static.raspberrypi.org/branches/main/web-component.js", "https://staging-editor-static.raspberrypi.org/branches/main/scratch.html", "https://staging-editor-static.raspberrypi.org/branches/main/scratch.js", "https://staging-editor-static.raspberrypi.org/latest_version", "https://staging-editor-static.raspberrypi.org/branches/main/html-renderer.html", "https://staging-editor-static.raspberrypi.org/branches/main/html-renderer.js" ] }The PR also uploads latest_version with Cache-Control: no-cache, because that file is intentionally updated in place.
For production tags, before it purged individual files inside one release plus latest_version. Now it purges:
{ "prefixes": [ "editor-static.raspberrypi.org/releases/<tag>/", "editor-static.raspberrypi.org/latest_version" ] }Why
Staging should serve the latest deployed version of editor-ui after each deploy.
The previous single-file purge targeted paths such as
web-component.js,scratch.js, andhtml-renderer.js. That can be unreliable because Cloudflare may cache separate variants of the same URL when request headers differ, for example with different Origin headers. If the purge request does not match the cached variant, Cloudflare can continue serving an older file. Prefix purging clears the deployed build path as a unit. The next request after deploy fetches the updated files from the bucket, and Cloudflare then caches those files again as normal.This is a targeted deploy/cache invalidation fix.
References:
Idea:
Longer term, we should move to content-hashed asset filenames with immutable caching, leaving only small stable entrypoints or manifests as revalidated files.