go-13 (dnscontrol/lazysql, árboles de deps Go enormes) destapó otra race del watchdog: durante el fetch/'go mod vendor'/resolve_phases (host-side, antes del bwrap) el árbol no está bind-montado ⇒ el watchdog lo borraba a mitad del vendor → go.mod desaparecía → 'receta sin compile, heurística no encontró build system'. Ahora además protege work/sources/<name>-* si <name> tiene un proceso 'hammer build' activo (cubre toda la vida del build, no solo la fase sandbox).
74 lines
4.2 KiB
Bash
Executable File
74 lines
4.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# farm-worker-loop.sh — loop AUTÓNOMO del worker. Construye la cola recipes/incoming/ en
|
|
# bucle (PROMOTE=0: sólo sella al store local, NO promueve, NO firma, NO toca gitea), con
|
|
# watchdog de disco integrado. El hub (laptop) le mete recetas nuevas vía farm-sync.sh y le
|
|
# baja el store sellado; este loop sólo muele lo que haya, 24/7, sin esperar a nadie.
|
|
#
|
|
# Idempotente: cada ciclo re-escanea incoming/; lo ya-sellado sale por cache-hit (instantáneo),
|
|
# sólo construye lo nuevo. Cuando la cola está toda construida, duerme IDLE_SLEEP y reintenta.
|
|
#
|
|
# Lo lanza systemd (hammer-farm.service). Manual: JOBS=2 ./scripts/farm/farm-worker-loop.sh
|
|
set -uo pipefail
|
|
HAMMER_DIR="${HAMMER_DIR:-/opt/hammer}"
|
|
cd "$HAMMER_DIR"
|
|
. "$HOME/.cargo/env" 2>/dev/null || true
|
|
JOBS="${JOBS:-$(nproc)}"
|
|
IDLE_SLEEP="${IDLE_SLEEP:-300}"
|
|
|
|
# --- watchdog de disco: cada 3 min borra work/sources/* que ningún bwrap activo bind-monta
|
|
# (seguro: sellada=store CAS, en-cola=se re-extrae sola). Evita que el vendoring llene el disco.
|
|
# Además, si el disco supera DISK_HIGH%, purga los CACHES Go (GOMODCACHE ~/go/pkg/mod + gocache):
|
|
# el `go mod vendor` de las recetas Go acumula ahí decenas de GB sin tope (el vendor/ local de cada
|
|
# receta ya tiene lo que el build necesita; el modcache sólo se usa DURANTE el vendor). Si la purga
|
|
# pisa un vendor en curso, esa receta reintenta el próximo ciclo (cache-hit el resto). Sin esto, una
|
|
# tanda Go grande llena el disco de 80G y el I/O-wait dispara el load (cuello real, no CPU/RAM).
|
|
DISK_HIGH="${DISK_HIGH:-82}"
|
|
(
|
|
while :; do
|
|
sleep 180
|
|
# Protección 1: árboles que un bwrap activo bind-monta (fase compile dentro del sandbox).
|
|
active=$(pgrep -af bwrap 2>/dev/null | grep -oE 'work/sources/[^ ]+' | sort -u)
|
|
# Protección 2: árboles cuya receta tiene un `hammer build` EN VUELO. Durante el fetch/`go mod
|
|
# vendor`/resolve_phases (host-side, ANTES de que arranque el bwrap) el árbol no está bind-montado
|
|
# ⇒ la protección 1 no lo cubre. Una tanda Go con árbol de deps enorme (dnscontrol/lazysql) tarda
|
|
# minutos vendoreando; sin esto, el watchdog le borra el go.mod a mitad → "no build system".
|
|
building=$(pgrep -af 'release/hammer' 2>/dev/null | grep -oE '[^ ]+\.toml' | sed 's#.*/##;s#\.toml$##' | sort -u)
|
|
for d in work/sources/*/; do
|
|
[ -d "$d" ] || continue; dd=${d%/}
|
|
printf '%s\n' "$active" | grep -qxF "$dd" && continue
|
|
nm=$(basename "$dd"); nm=${nm%-*} # work/sources/<name>-<sha40> → <name> (el sha no trae '-')
|
|
printf '%s\n' "$building" | grep -qxF "$nm" && continue
|
|
rm -rf "$dd"
|
|
done
|
|
use=$(df --output=pcent "$HAMMER_DIR" 2>/dev/null | tr -dc '0-9')
|
|
if [ -n "$use" ] && [ "$use" -ge "$DISK_HIGH" ]; then
|
|
# OJO: `go clean -modcache` borra ~/go/pkg/mod ENTERO. Si lo corre mientras un `go mod vendor`
|
|
# del fetch está bajando módulos, le arranca el cache bajo los pies (`.partial: no such file`)
|
|
# y ESE vendor falla — y con tandas pesadas (k8s/azure SDK, varios GB en paralelo) son MUCHOS a
|
|
# la vez ⇒ el lote no converge. La purga de work/sources de arriba ya liberó lo grueso (segura:
|
|
# saltea bind-montadas). Sólo purgo el modcache si NO hay vendor de host activo; si lo hay,
|
|
# difiero al próximo tick (el sandbox `go install` usa GOPATH=/tmp + -mod=vendor ⇒ no toca el
|
|
# modcache del host, así que purgar durante un build sandbox sigue siendo seguro).
|
|
if pgrep -f 'go mod vendor' >/dev/null 2>&1; then
|
|
echo "$(date -u +%FT%TZ) watchdog: disco ${use}% ≥ ${DISK_HIGH}% pero hay vendor activo ⇒ difiero purga modcache"
|
|
else
|
|
echo "$(date -u +%FT%TZ) watchdog: disco ${use}% ≥ ${DISK_HIGH}% ⇒ purgo caches Go"
|
|
go clean -modcache 2>/dev/null; go clean -cache 2>/dev/null
|
|
fi
|
|
fi
|
|
done
|
|
) &
|
|
|
|
echo "$(date -u +%FT%TZ) worker-loop arrancado: JOBS=$JOBS IDLE_SLEEP=$IDLE_SLEEP"
|
|
while :; do
|
|
n=$(ls recipes/incoming/*.toml 2>/dev/null | wc -l)
|
|
if [ "$n" -gt 0 ]; then
|
|
echo "$(date -u +%FT%TZ) ciclo: $n recetas en cola"
|
|
JOBS="$JOBS" PROMOTE=0 scripts/build-farm.sh 2>&1 | tail -50
|
|
echo "$(date -u +%FT%TZ) ciclo terminado; store sellado disponible para el hub"
|
|
else
|
|
echo "$(date -u +%FT%TZ) cola vacía; durmiendo ${IDLE_SLEEP}s"
|
|
fi
|
|
sleep "$IDLE_SLEEP"
|
|
done
|