874b6f20c2
Основа — Horizon (MIT). История апстрима не переносится: этот репозиторий ведёт свою.
77 lines
4.1 KiB
Bash
Executable File
77 lines
4.1 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Keeps the Mac mini's Horizon runners from filling its disk. launchd runs a copy taken from main
|
|
# (~/.actions-runners/runner-gc.sh, never a pull request's checkout) every 6 hours; see docs/release-flow.md.
|
|
# - A runner in the middle of a job is left alone.
|
|
# - A checkout whose cargo build folders (target/ and the harness probes' targets under .local/, the
|
|
# directories holding a CACHEDIR.TAG) pass MAX_TARGET_GB loses them: sccache (tools/ci/runner-env.sh)
|
|
# makes the next build cheap. Symlinks into the shared vanilla data are never followed.
|
|
# - Harness work folders under .local/ (vanilla exports, probe outputs: real directories, not the links into
|
|
# the shared vanilla data) that nothing touched for STALE_DAYS go; a harness that runs again rebuilds its own.
|
|
# .local/parity-runner (run state, oracle cache) stays.
|
|
# - The shared prepared resources keep their KEEP_PREPARED newest preparations, only while no runner works.
|
|
# - Java processes harnesses left behind (vanilla servers, oracles) go once ORPHAN_HOURS old: those whose parent
|
|
# is gone (adopted by launchd, init or systemd --user) and whose command line names a runner's checkout or a
|
|
# worktree's .local/. A job cancelled while it ran left such servers for days (2026-10-26); tools/parity.py now
|
|
# stops its harnesses on SIGTERM, and this catches what it can't (SIGKILL, a harness run by hand).
|
|
set -euo pipefail
|
|
root=${RUNNERS:-$HOME/.actions-runners}
|
|
max_kb=$(( ${MAX_TARGET_GB:-12} * 1024 * 1024 ))
|
|
keep=${KEEP_PREPARED:-2}
|
|
stale_min=$(( ${STALE_DAYS:-3} * 24 * 60 ))
|
|
busy() { pgrep -f "$1/bin/Runner.Worker" > /dev/null; }
|
|
|
|
any_busy=0
|
|
for runner in "$root"/horizon "$root"/horizon-[0-9]*; do
|
|
[ -d "$runner/_work" ] || continue
|
|
if busy "$runner"; then echo "$(basename "$runner"): in a job, skipped"; any_busy=1; continue; fi
|
|
rm -rf "${runner:?}/_work/_temp/"* 2>/dev/null || true
|
|
checkout="$runner/_work/horizon/horizon"
|
|
[ -d "$checkout" ] || continue
|
|
stale=0
|
|
for dir in "$checkout"/.local/*/; do
|
|
dir=${dir%/}
|
|
[ -L "$dir" ] || [ "$(basename "$dir")" = parity-runner ] && continue
|
|
if [ -z "$(find "$dir" -mmin -"$stale_min" -print -quit 2>/dev/null)" ]; then rm -rf "$dir"; stale=$((stale + 1)); fi
|
|
done
|
|
[ "$stale" = 0 ] || echo "$(basename "$runner"): removed $stale harness folders untouched for ${STALE_DAYS:-3} days"
|
|
targets=()
|
|
[ -f "$checkout/target/CACHEDIR.TAG" ] && targets+=("$checkout/target")
|
|
while IFS= read -r tag; do targets+=("$(dirname "$tag")"); done < <(
|
|
find "$checkout/.local" -mindepth 2 -maxdepth 2 -name CACHEDIR.TAG -type f 2>/dev/null)
|
|
[ ${#targets[@]} -gt 0 ] || continue
|
|
size=$(du -sk "${targets[@]}" | awk '{s += $1} END {print s}')
|
|
if [ "$size" -gt "$max_kb" ]; then
|
|
rm -rf "${targets[@]}"
|
|
echo "$(basename "$runner"): removed ${#targets[@]} build folders ($(( size / 1024 / 1024 )) GB)"
|
|
fi
|
|
done
|
|
|
|
# [[dd-]hh:]mm:ss, as ps prints a process's age, in minutes.
|
|
minutes() {
|
|
local t=$1 d=0 h=0 m a b c
|
|
if [[ $t == *-* ]]; then d=${t%%-*}; t=${t#*-}; fi
|
|
IFS=: read -r a b c <<< "$t"
|
|
if [ -n "$c" ]; then h=$a m=$b; else m=$a; fi
|
|
echo $(( 10#$d * 1440 + 10#$h * 60 + 10#$m ))
|
|
}
|
|
orphan_min=$(( ${ORPHAN_HOURS:-3} * 60 ))
|
|
ps -A -o pid=,ppid=,etime=,command= | while read -r pid ppid etime command; do
|
|
case "$command" in *java*) ;; *) continue ;; esac
|
|
case "$command" in *"$root"/*/_work/*|*/.claude/worktrees/*/.local/*|*/code/horizon/.local/*) ;; *) continue ;; esac
|
|
[ "$(minutes "$etime")" -ge "$orphan_min" ] || continue
|
|
if [ "$ppid" != 1 ]; then
|
|
case "$(ps -o command= -p "$ppid" 2>/dev/null)" in *"systemd --user"*) ;; *) continue ;; esac
|
|
fi
|
|
if kill "$pid" 2>/dev/null; then echo "orphaned java $pid ($etime old) stopped: ${command:0:160}"; fi
|
|
done
|
|
|
|
prepared="$root/horizon/_work/horizon/shared-local/prepared"
|
|
if [ "$any_busy" = 0 ] && [ -d "$prepared" ] && mkdir "$prepared/.lock" 2>/dev/null; then
|
|
trap 'rmdir "$prepared/.lock" 2>/dev/null || true' EXIT
|
|
ls -1t "$prepared" | tail -n +"$(( keep + 1 ))" | while read -r old; do
|
|
rm -rf "${prepared:?}/$old"
|
|
echo "prepared resources $old removed"
|
|
done
|
|
fi
|
|
df -h "$root" | tail -1
|