Skip to content

Commit d5c1f1d

Browse files
authored
Schedule cleanup of stale julia caches on long-lived branches (#14414)
* Schedule cleanup of stale julia caches on long-lived branches julia-actions/cache@v3 intentionally skips delete-old-caches on the default branch, so caches on main and v1.9 accumulate without bound. Add a daily matrix job that keeps the newest julia cache per (workflow, os) tuple and deletes the rest. * Filter julia caches at source in cleanup workflow Non-julia caches could otherwise fill the first 100 rows of gh cache list and push stale julia entries out of the window, leaving them uncleaned.
1 parent e4b75c1 commit d5c1f1d

1 file changed

Lines changed: 88 additions & 2 deletions

File tree

.github/workflows/cleanup-caches.yml

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Cleanup github runner caches on closed pull requests
1+
name: Cleanup github runner caches
22
on:
33
# pull_request_target is required so fork PRs can delete their own caches on close.
44
# pull_request from a fork ships a read-only GITHUB_TOKEN regardless of the
@@ -7,9 +7,17 @@ on:
77
pull_request_target:
88
types:
99
- closed
10+
# Daily cleanup of stale julia caches on long-lived branches. julia-actions/cache@v3
11+
# does not run delete-old-caches on the default branch (by design, to avoid races
12+
# between concurrent runs), so caches accumulate. This job keeps only the newest
13+
# cache per (workflow, os) tuple.
14+
schedule:
15+
- cron: "0 4 * * *"
16+
workflow_dispatch:
1017

1118
jobs:
12-
cleanup:
19+
cleanup-pr:
20+
if: github.event_name == 'pull_request_target'
1321
runs-on: ubuntu-latest
1422
permissions:
1523
actions: write
@@ -65,3 +73,81 @@ jobs:
6573
GH_TOKEN: ${{ github.token }}
6674
GH_REPO: ${{ github.repository }}
6775
BRANCH: refs/pull/${{ github.event.pull_request.number }}/merge
76+
77+
cleanup-branches:
78+
if: github.event_name == 'schedule' || github.event_name == 'workflow_dispatch'
79+
runs-on: ubuntu-latest
80+
permissions:
81+
actions: write
82+
strategy:
83+
fail-fast: false
84+
matrix:
85+
ref:
86+
- refs/heads/main
87+
- refs/heads/v1.9
88+
steps:
89+
- name: Cleanup stale julia caches on ${{ matrix.ref }}
90+
run: |
91+
echo "::group::Julia cache list for $REF"
92+
93+
# Filter at source with --key (prefix match) so non-julia caches
94+
# don't push stale julia entries past the --limit window.
95+
caches=$(gh cache list --ref "$REF" --key julia-cache --limit 100 --json id,key,createdAt,sizeInBytes)
96+
total=$(echo "$caches" | jq 'length')
97+
98+
echo "Found $total julia cache(s) on $REF"
99+
100+
if [ "$total" -eq 0 ]; then
101+
echo "::endgroup::"
102+
echo "::notice::No julia caches on $REF"
103+
exit 0
104+
fi
105+
106+
# Group key is the cache key with run_id=... onwards stripped.
107+
# Sort by createdAt descending so the newest cache per group comes first;
108+
# awk keeps the first occurrence of each group (newest) and prints the rest.
109+
toDelete=$(echo "$caches" \
110+
| jq -r '.[] | "\(.createdAt)|\(.id)|\(.sizeInBytes)|\(.key | split(";run_id=") | .[0])"' \
111+
| sort -r \
112+
| awk -F'|' 'seen[$4]++ { print $2 "|" $3 "|" $4 }')
113+
114+
deleteCount=$(echo "$toDelete" | grep -c '|' || true)
115+
keepCount=$((total - deleteCount))
116+
117+
echo "Will delete $deleteCount stale cache(s), keep $keepCount newest per (workflow, os)"
118+
echo "::endgroup::"
119+
120+
if [ "$deleteCount" -eq 0 ]; then
121+
echo "::notice::Nothing to delete on $REF - all caches are already the newest per (workflow, os)"
122+
exit 0
123+
fi
124+
125+
## Do not fail the workflow on a single delete error.
126+
set +e
127+
128+
echo "::group::Deleting stale caches"
129+
deleted=0
130+
failed=0
131+
freedMb=0
132+
133+
while IFS='|' read -r id size group; do
134+
[ -z "$id" ] && continue
135+
mb=$((size / 1024 / 1024))
136+
echo "Deleting cache $id (${mb}MB) - group: $group"
137+
if gh cache delete "$id"; then
138+
echo " ✓ deleted"
139+
deleted=$((deleted + 1))
140+
freedMb=$((freedMb + mb))
141+
else
142+
echo " ✗ failed"
143+
failed=$((failed + 1))
144+
fi
145+
done <<< "$toDelete"
146+
147+
echo "::endgroup::"
148+
149+
echo "::notice::Cleanup complete on $REF: $deleted deleted (${freedMb}MB freed), $failed failed"
150+
env:
151+
GH_TOKEN: ${{ github.token }}
152+
GH_REPO: ${{ github.repository }}
153+
REF: ${{ matrix.ref }}

0 commit comments

Comments
 (0)