diff --git a/scripts/respaldo-storagebox.sh b/scripts/respaldo-storagebox.sh index b1e2bcd9..5c6c6363 100755 --- a/scripts/respaldo-storagebox.sh +++ b/scripts/respaldo-storagebox.sh @@ -66,6 +66,36 @@ SSH_CMD="ssh -4 -p $SB_PORT -i $KEY -o StrictHostKeyChecking=accept-new -o Serve # Opciones comunes. `--partial-dir` es lo que hace el respaldo continuable a mitad de fichero. RS="rsync -a --partial-dir=.rsync-partial --info=progress2 -z --compress-choice=zstd --compress-level=3" +# ── REINTENTOS: EL ENLACE SE CAE, Y ESO NO ES EXCEPCIONAL ─────────────────────────────────────── +# Primera corrida real (2026-08-07): tras subir el cerebro y 2,3 G de store, murió con +# `Connection reset by peer` / `Broken pipe` y rsync salió con 255. Con una subida de ~19 h sobre un +# enlace de oficina, que la conexión se corte no es un accidente: es lo NORMAL. Un respaldo que hay +# que relanzar a mano cada vez que se cae no se completa nunca, porque nadie está mirando. +# +# Como rsync ya es incremental y `--partial-dir` conserva los trozos, reintentar es barato y seguro: +# cada intento retoma donde quedó. El bucle sólo insiste ante fallos de RED (códigos 10/12/23/30/35/ +# 255); un error de verdad —permisos, disco lleno en destino, ruta inexistente— sale a la primera en +# vez de repetirse 40 veces contra la misma pared. +reintentar() { + etiqueta="$1"; shift + intento=1 + while :; do + "$@" && return 0 + rc=$? + case "$rc" in + 10|12|23|30|35|255) ;; # red / pipe roto / timeout: insistir + *) echo "!! $etiqueta: error $rc que NO es de red — no reintento"; return "$rc" ;; + esac + if [ "$intento" -ge 40 ]; then + echo "!! $etiqueta: 40 intentos y sigue cayéndose. Dejo lo subido y paro."; return "$rc" + fi + espera=$(( intento < 6 ? intento * 10 : 60 )) + echo ".. $etiqueta: corte de red (rsync $rc). Intento $intento; reanudo en ${espera}s." + intento=$((intento + 1)) + sleep "$espera" + done +} + if ! $SSH_CMD "$SB_USER@$SB_HOST" 'df -h .' >/dev/null 2>&1; then echo "!! No hay SSH al Storage Box ($SB_HOST:$SB_PORT)." echo "!! Si acabás de crearlo, el DNS tarda unos minutos en propagar. Reintentá." @@ -77,10 +107,10 @@ $SSH_CMD "$SB_USER@$SB_HOST" 'mkdir hammer hammer/store hammer/repo hammer/estad # ── 1. EL CEREBRO: estado + repo. Minutos, y es lo que no se puede perder. ────────────────────── echo "==> [1/3] estado (el grafo: qué había construido y con qué hash)" -$RS $SECO -e "$SSH_CMD" "$RAIZ/docs/state/" "$SB_USER@$SB_HOST:hammer/estado/" || true +reintentar estado $RS $SECO -e "$SSH_CMD" "$RAIZ/docs/state/" "$SB_USER@$SB_HOST:hammer/estado/" || true echo "==> [2/3] repo (recetas, scripts, SDDs — el cerebro; con esto solo se reconstruye el store)" -$RS --delete $SECO -e "$SSH_CMD" \ +reintentar repo $RS --delete $SECO -e "$SSH_CMD" \ --exclude /store --exclude /store-rust --exclude /store-kern \ --exclude /work --exclude /target --exclude /.dev-fs --exclude /dist --exclude /.scratch \ "$RAIZ/" "$SB_USER@$SB_HOST:hammer/repo/" @@ -92,10 +122,10 @@ echo "==> [3/3] store (128 G a 8 Mbps ⇒ NO cabe en una sentada; esto se corta HUER="$(ls -t "$RAIZ"/work/store-gc-huerfanos-*.txt 2>/dev/null | head -1)" if [ -n "$HUER" ] && [ -s "$HUER" ]; then echo " · huérfanos primero ($(wc -l < "$HUER") artefactos, únicos ejemplares) — desde $HUER" - $RS $SECO -e "$SSH_CMD" --files-from="$HUER" "$RAIZ/store/" "$SB_USER@$SB_HOST:hammer/store/" || true + reintentar huerfanos $RS $SECO -e "$SSH_CMD" --files-from="$HUER" "$RAIZ/store/" "$SB_USER@$SB_HOST:hammer/store/" || true fi echo " · resto del store" -$RS $SECO -e "$SSH_CMD" "$RAIZ/store/" "$SB_USER@$SB_HOST:hammer/store/" +reintentar store $RS $SECO -e "$SSH_CMD" "$RAIZ/store/" "$SB_USER@$SB_HOST:hammer/store/" echo "==> ocupación en el Storage Box:" $SSH_CMD "$SB_USER@$SB_HOST" 'df -h .' 2>/dev/null | tail -2