build-cran-binaries/scripts/purge_cdn_zone.sh
pat-s 7dc84d590b
fix(rebuild): re-index and purge the CDN after a rebuild
A rebuild replaces an object in place: a package whose build failed was
published as its CRAN source, and the rebuilt binary takes exactly the same
URL. Two things then hide the result from clients.

The slot's index still advertises the old MD5 and, for anything served from
source, no Built stamp, because weekly-rebuild-missing never re-indexed. And
the pull zone caches tarballs for ~370 days, while purge_cdn_cache.sh only
purges the five index files, so the edge keeps serving the source tarball for
up to a year with nothing about it looking wrong.

Observed after rebuilding AATtools 0.0.3: the pipeline reported a successful
upload while the edge still served the CRAN source, etag ea8127... and no Meta/.

- re-index the slot at the end of a rebuild, flat and per-minor, detecting the
  codename from the image rather than adding OS_ID to 18 matrix rows
- add scripts/purge_cdn_zone.sh and call it afterwards. One zone purge covers
  every replaced object and all three hostnames, which share pull zone 3857050;
  purging per URL would be ~13.5k rate-limited calls per arch where one missed
  call leaves a silently stale package
- purge on failure too, since a rebuild that died part-way still replaced
  objects and those are exactly the ones a stale edge keeps hiding
2026-08-09 18:31:23 +00:00

52 lines
1.8 KiB
Shell
Executable file

#!/usr/bin/env bash
#
# Purge the entire BunnyCDN pull zone.
#
# `purge_cdn_cache.sh` purges the five index files by URL, which is right after
# a normal update: new packages arrive at new URLs, so only the index is stale.
#
# A rebuild is different. It replaces an object *in place*: a package whose
# build failed was published as its CRAN source, and the rebuilt binary takes
# exactly the same URL. The zone caches tarballs for ~370 days
# (`cache_expiration_time` in cdn.tf), so without a purge every client keeps
# receiving the source tarball for up to a year, and nothing about it looks
# wrong from the outside.
#
# Purging per URL would mean one API call per replaced package -- ~13.5k per
# arch against a rate-limited endpoint, where a single missed call leaves a
# silently stale package. One zone purge is a single call regardless of how many
# objects were replaced. The cost is a cold cache for everything else, which is
# why this is not used by the daily update path.
#
# All hostnames on the zone (cran.devxy.io, cran.allianceswisspass.devxy.io,
# cran.rpkgs.com) share pull zone 3857050, so one purge covers all of them.
#
# Usage:
# purge_cdn_zone.sh <BUNNYNET_API_KEY> <pull_zone_id>
#
set -euo pipefail
if (($# < 2)); then
echo "usage: $0 <api_key> <pull_zone_id>" >&2
exit 2
fi
api_key="$1"
zone_id="$2"
echo "Purging BunnyCDN pull zone ${zone_id}"
status=$(
curl -sS -o /tmp/purge_zone_response.txt -w '%{http_code}' -X POST \
-H "AccessKey: ${api_key}" \
-H "Content-Length: 0" \
"https://api.bunny.net/pullzone/${zone_id}/purgeCache"
)
if [[ "${status}" != "200" && "${status}" != "204" ]]; then
echo "Purge of pull zone ${zone_id} failed with HTTP ${status}:" >&2
cat /tmp/purge_zone_response.txt >&2
exit 1
fi
echo "Purged pull zone ${zone_id} (HTTP ${status})"