Cache Management #12
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
name: Cache Management | |
on: | |
schedule: | |
- cron: '0 0 */2 * *' | |
workflow_dispatch: | |
inputs: | |
force_warmup: | |
description: 'Force cache warmup regardless of age' | |
required: false | |
default: false | |
type: boolean | |
jobs: | |
cleanup-cache: | |
runs-on: ubuntu-latest | |
permissions: | |
actions: write | |
steps: | |
- name: Cleanup old caches | |
uses: actions/github-script@v7 | |
with: | |
script: | | |
const retentionCount = 2; // Keep the 2 most recent caches per prefix | |
const forceWarmupDays = 5; // Force warmup if newest cache is older than this | |
const caches = await github.rest.actions.getActionsCacheList({ | |
owner: context.repo.owner, | |
repo: context.repo.repo | |
}); | |
// Track if any cache needs warming up | |
let needsWarmup = false; | |
// Group caches by their prefix pattern (e.g., sccache-Windows-cuda-main) | |
const cacheGroups = {}; | |
for (const cache of caches.data.actions_caches) { | |
if (cache.key.startsWith('sccache-')) { | |
// Extract the prefix pattern (everything before the last hyphen + timestamp) | |
const prefixPattern = cache.key.replace(/-\d+$/, ''); | |
if (!cacheGroups[prefixPattern]) { | |
cacheGroups[prefixPattern] = []; | |
} | |
cacheGroups[prefixPattern].push(cache); | |
} | |
} | |
const now = new Date(); | |
// Process each group of caches | |
for (const prefix in cacheGroups) { | |
// Sort caches by creation date (newest first) | |
const sortedCaches = cacheGroups[prefix].sort((a, b) => | |
new Date(b.created_at) - new Date(a.created_at)); | |
// Check if most recent cache is older than forceWarmupDays | |
if (sortedCaches.length > 0) { | |
const newestCache = sortedCaches[0]; | |
const createdAt = new Date(newestCache.created_at); | |
const ageInDays = (now - createdAt) / (1000 * 60 * 60 * 24); | |
if (ageInDays > forceWarmupDays) { | |
console.log(`Cache ${prefix} is stale (${ageInDays.toFixed(1)} days old). Will force warmup.`); | |
needsWarmup = true; | |
} | |
// Log the kept most recent cache | |
console.log(`Keeping most recent cache: ${newestCache.key}, created ${ageInDays.toFixed(1)} days ago`); | |
// Keep second most recent cache if it exists | |
if (sortedCaches.length > 1) { | |
const secondCache = sortedCaches[1]; | |
const secondCreatedAt = new Date(secondCache.created_at); | |
const secondAgeInDays = (now - secondCreatedAt) / (1000 * 60 * 60 * 24); | |
console.log(`Keeping second most recent cache: ${secondCache.key}, created ${secondAgeInDays.toFixed(1)} days ago`); | |
} | |
} | |
// Delete all caches beyond the retention count | |
for (let i = retentionCount; i < sortedCaches.length; i++) { | |
const cache = sortedCaches[i]; | |
const createdAt = new Date(cache.created_at); | |
const ageInDays = (now - createdAt) / (1000 * 60 * 60 * 24); | |
console.log(`Deleting old cache: ${cache.key}, created ${ageInDays.toFixed(1)} days ago`); | |
await github.rest.actions.deleteActionsCacheByKey({ | |
owner: context.repo.owner, | |
repo: context.repo.repo, | |
key: cache.key | |
}); | |
} | |
} | |
// Set output to control whether to run warmup jobs | |
core.setOutput('needs_warmup', needsWarmup.toString()); | |
warmup-unix: | |
needs: cleanup-cache | |
if: ${{ needs.cleanup-cache.outputs.needs_warmup == 'true' || (github.event_name == 'workflow_dispatch' && github.event.inputs.force_warmup == 'true') }} | |
runs-on: ${{ matrix.os }} | |
strategy: | |
matrix: | |
os: [ubuntu-22.04, macos-15] | |
device: [cpu, metal, cuda] | |
exclude: | |
- os: macos-15 | |
device: cpu | |
- os: macos-15 | |
device: cuda | |
- os: ubuntu-22.04 | |
device: metal | |
container: ${{ matrix.device == 'cuda' && 'nvidia/cuda:12.8.0-devel-ubuntu22.04' || '' }} | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Run sccache-cache | |
uses: mozilla-actions/sccache-action@v0.0.7 | |
- name: Configure sccache | |
id: sccache | |
run: | | |
mkdir -p "$PWD/bindings/.sccache" | |
export SCCACHE_DIR="$PWD/bindings/.sccache" | |
echo "SCCACHE_DIR=$SCCACHE_DIR" >> $GITHUB_ENV | |
- name: Cache sccache storage | |
uses: actions/cache@v4 | |
with: | |
path: ${{ env.SCCACHE_DIR }} | |
key: sccache-${{ runner.os }}-${{ matrix.device }}-${{ github.ref_name }}-${{ github.run_id }} | |
restore-keys: | | |
sccache-${{ runner.os }}-${{ matrix.device }}-${{ github.ref_name }}- | |
sccache-${{ runner.os }}-${{ matrix.device }}- | |
warmup-win: | |
needs: cleanup-cache | |
if: ${{ needs.cleanup-cache.outputs.needs_warmup == 'true' || (github.event_name == 'workflow_dispatch' && github.event.inputs.force_warmup == 'true') }} | |
runs-on: ${{ matrix.os }} | |
strategy: | |
matrix: | |
os: [windows-2022] | |
device: [cpu, cuda] | |
steps: | |
- uses: actions/checkout@v4 | |
- name: Run sccache-cache | |
uses: mozilla-actions/sccache-action@v0.0.7 | |
- name: Configure sccache | |
run: | | |
New-Item -ItemType Directory -Force -Path "$PWD/bindings/.sccache" | |
$env:SCCACHE_DIR="$PWD/bindings/.sccache" | |
echo "SCCACHE_DIR=$env:SCCACHE_DIR" >> $env:GITHUB_ENV | |
- name: Cache sccache storage | |
uses: actions/cache@v4 | |
with: | |
path: ${{ env.SCCACHE_DIR }} | |
key: sccache-${{ runner.os }}-${{ matrix.device }}-${{ github.ref_name }}-${{ github.run_id }} | |
restore-keys: | | |
sccache-${{ runner.os }}-${{ matrix.device }}-${{ github.ref_name }}- | |
sccache-${{ runner.os }}-${{ matrix.device }}- |