Skip to content

Cache Hygiene

Cache Hygiene #8

Workflow file for this run

---
name: Cache Hygiene
on:
schedule:
- cron: "35 2 * * 1" # Weekly on Monday (UTC)
workflow_dispatch:
inputs:
dry_run:
description: "Preview deletions without removing caches"
required: false
default: true
type: boolean
permissions:
actions: write
contents: read
concurrency:
group: cache-hygiene
cancel-in-progress: true
jobs:
cleanup:
name: Cleanup stale caches
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Prune old workflow caches
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
EVENT_NAME: ${{ github.event_name }}
INPUT_DRY_RUN: ${{ inputs.dry_run || 'false' }}
run: |
set -euo pipefail
dry_run="false"
if [ "$EVENT_NAME" = "workflow_dispatch" ] && [ "$INPUT_DRY_RUN" = "true" ]; then
dry_run="true"
fi
api="https://api.github.com/repos/${GITHUB_REPOSITORY}/actions/caches?per_page=100"
payload="$(curl -fsSL \
-H "Authorization: Bearer ${GH_TOKEN}" \
-H "Accept: application/vnd.github+json" \
"$api")"
total="$(jq -r '.total_count' <<<"$payload")"
echo "Found ${total} cache entries. dry_run=${dry_run}"
delete_for_prefix() {
local prefix="$1"
local keep="$2"
mapfile -t rows < <(jq -r --arg p "$prefix" --argjson keep "$keep" '
[ .actions_caches[]
| select(.key | startswith($p))
| { id, key, last_accessed_at }
]
| sort_by(.last_accessed_at)
| reverse
| .[$keep:][]?
| "\(.id)\t\(.key)\t\(.last_accessed_at)"
' <<<"$payload")
if [ "${#rows[@]}" -eq 0 ]; then
echo "No stale caches for prefix=${prefix}"
return
fi
for row in "${rows[@]}"; do
id="${row%%$'\t'*}"
rest="${row#*$'\t'}"
key="${rest%%$'\t'*}"
last="${rest#*$'\t'}"
if [ "$dry_run" = "true" ]; then
echo "[dry-run] delete id=${id} key=${key} last_accessed=${last}"
else
echo "Deleting id=${id} key=${key} last_accessed=${last}"
curl -fsSL -X DELETE \
-H "Authorization: Bearer ${GH_TOKEN}" \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/${GITHUB_REPOSITORY}/actions/caches/${id}" \
>/dev/null
fi
done
}
# Keep a small hot set per cache family.
delete_for_prefix "codeql-overlay-base-database-" 4
delete_for_prefix "css-build-" 2
delete_for_prefix "zola-" 2