Files
SashegDev 874b6f20c2 Клиент: начальный импорт кодовой базы
Основа — Horizon (MIT). История апстрима не переносится: этот репозиторий ведёт свою.
2026-10-29 22:04:28 +03:00

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