Skip to content

Cache fixing by unit path invalidation instead of individual file listing#1464

Open
abcampo-iry wants to merge 2 commits into
mainfrom
issues/1371-purge-correctly-cache
Open

Cache fixing by unit path invalidation instead of individual file listing#1464
abcampo-iry wants to merge 2 commits into
mainfrom
issues/1371-purge-correctly-cache

Conversation

@abcampo-iry
Copy link
Copy Markdown
Contributor

@abcampo-iry abcampo-iry commented May 13, 2026

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, and html-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.

@abcampo-iry abcampo-iry temporarily deployed to previews/1464/merge May 13, 2026 09:49 — with GitHub Actions Inactive
@abcampo-iry abcampo-iry changed the title DRAFT | Purge files Cache Invalidation update May 13, 2026
@abcampo-iry abcampo-iry marked this pull request as ready for review May 13, 2026 10:54
Copilot AI review requested due to automatic review settings May 13, 2026 10:54
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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_version to S3 with Cache-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.

@abcampo-iry abcampo-iry changed the title Cache Invalidation update Trying to fix cache, by unit invalidation instead of cherry-picked May 13, 2026
@abcampo-iry abcampo-iry changed the title Trying to fix cache, by unit invalidation instead of cherry-picked Cache fixing by unit path invalidation instead of individual file listing May 13, 2026
Comment on lines +184 to +209
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"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

@zetter-rpf
Copy link
Copy Markdown
Contributor

Thanks for the explanation and links to the doc. I've added a comment.

I also wondered if we set a no cache for latest-version, do we need to purge it any more?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants