granja: DEAD-MAN SWITCH — el worker se borra solo tras 1h idle
hworker-4 estuvo 5 DÍAS idle (carga 0.00, sin crontab, sin loops, 37G de KDE sin cosechar) quemando dinero. El usuario había pedido esto explícitamente —"los vps se autoapagan cuando se detectan idle por un tiempo"— y de sus 3 puntos (volumen / auto-apagado / cosecha) implementé el 1 y el 3. Éste faltaba. EL FALLO ERA ESTRUCTURAL, no un olvido: farm-down.sh existe pero es MANUAL. El modelo "efímero" dependía de que el agente se acordara de llamarlo — y si su contexto se corta, o la sesión muere, el server queda vivo para siempre. Un invariante que necesita que alguien recuerde NO es un invariante. Por eso el switch vive EN EL WORKER: para apagarse no necesita ni al hub ni a mí. BORRA, no apaga: en Hetzner un server apagado SIGUE COBRANDO (disco + IP). Un poweroff daría sensación de ahorro y seguiría facturando. Precio: el token vive en el worker (/etc/hammer-deadman.env 0600). Riesgo real y consciente; se acepta porque la alternativa MEDIDA fue peor: 5 días de VPS idle. Cuenta por INACTIVIDAD CONTINUA, no por antigüedad: cualquier señal de trabajo (hammer build, worker-loop, heartbeat <30min) resetea los ticks. Guarda /var/lib/hammer-no-borrar aborta el borrado si hay cosecha pendiente. systemd timer y NO cron, por la lección medida: un cron "validado a mano" nunca disparó porque el PID 1 de aquella máquina (arje-zero) no tenía crond. Validar la LÍNEA no es validar que un demonio la ejecute. y el farm-up comprueban que el timer quedó ACTIVO — evidencia, no fe. Cableado en farm-up: todo worker NACE con el switch puesto. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -57,6 +57,33 @@ for k in $(seq 1 "$N"); do
|
||||
./ "root@$ip:$REMOTE/"
|
||||
# el servicio ya arrancó en el boot (baked/enabled); reiniciar fuerza rescan inmediato de la cola
|
||||
$SSH root@"$ip" 'systemctl restart hammer-farm' 2>/dev/null || true
|
||||
|
||||
# DEAD-MAN SWITCH: el worker se borra SOLO tras 1h sin trabajo. Va acá, en el nacimiento, porque
|
||||
# el modelo "efímero" NO puede depender de que alguien llame a farm-down: hworker-4 estuvo 5 días
|
||||
# idle (2026-07-17) justo por eso — el agente que lo creó se fue y el server quedó. Un invariante
|
||||
# que necesita que alguien se acuerde no es un invariante.
|
||||
echo " armando dead-man switch (1h idle ⇒ auto-delete)…"
|
||||
tok="${HCLOUD_TOKEN:-$(grep -shoE '^ *token *= *"?[A-Za-z0-9]+' "$HOME/.config/hcloud/cli.toml" 2>/dev/null | head -1 | sed 's/.*[= "]//')}"
|
||||
if [ -z "$tok" ]; then
|
||||
echo " ⚠ SIN TOKEN para el dead-man switch: este worker NO se auto-borrará."
|
||||
echo " (un poweroff no sirve: Hetzner cobra igual con el server apagado)"
|
||||
else
|
||||
scp -q -i "$SSH_KEY" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
|
||||
scripts/farm/deadman.sh "root@$ip:/usr/local/bin/deadman.sh" 2>/dev/null
|
||||
scp -q -i "$SSH_KEY" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
|
||||
scripts/farm/hammer-deadman.service scripts/farm/hammer-deadman.timer \
|
||||
"root@$ip:/etc/systemd/system/" 2>/dev/null
|
||||
$SSH root@"$ip" "chmod +x /usr/local/bin/deadman.sh
|
||||
printf 'HCLOUD_TOKEN=%s\n' '$tok' > /etc/hammer-deadman.env; chmod 600 /etc/hammer-deadman.env
|
||||
systemctl daemon-reload && systemctl enable --now hammer-deadman.timer" >/dev/null 2>&1
|
||||
# EVIDENCIA, no fe: que el timer esté ARMADO se comprueba, no se asume (el cron de aquella vez
|
||||
# estaba "validado" y nunca disparó porque el PID 1 no tenía crond).
|
||||
if $SSH root@"$ip" 'systemctl is-active hammer-deadman.timer' 2>/dev/null | grep -q active; then
|
||||
echo " ✓ dead-man armado: $($SSH root@"$ip" 'systemctl list-timers hammer-deadman.timer --no-pager 2>/dev/null | sed -n 2p' | awk '{print $1, $2, $3}')"
|
||||
else
|
||||
echo " ⚠ el timer NO quedó activo ⇒ este worker puede quedarse idle para siempre. Revisar."
|
||||
fi
|
||||
fi
|
||||
echo " ✓ $name muele la cola actual"
|
||||
done
|
||||
|
||||
|
||||
Reference in New Issue
Block a user