restic "repository is already locked": cuándo es seguro usar unlock
tras un kill -9 queda 1 lock; backup sigue funcionando (exit 0), forget --prune falla (exit 1) hasta ejecutar restic unlock, que quitó 1 lock.
Contenido
Este artículo no contiene enlaces de afiliado.
Si un backup de restic se corta (reinicio, OOM, kill -9), el siguiente forget --prune puede negarse con "repository is already locked". Se probó qué pasa exactamente y cuándo restic unlock es seguro.
Condiciones: restic 0.16.4 en Linux arm64, repositorio local, un fichero aleatorio de 200 MiB, contraseña desechable. No se probó con repositorios remotos (S3, rclone) ni con dos máquinas escribiendo a la vez. Script completo al final.
Qué ocurre
| Paso | Resultado |
|---|---|
Backup interrumpido con kill -9 a los 1,5 s |
queda 1 fichero en locks/ |
Nuevo restic backup |
exit 0: el backup usa un lock no exclusivo y convive con el viejo |
restic forget --keep-last 1 --prune |
exit 1: "repository is already locked by PID ..." |
restic unlock |
"successfully removed 1 locks", exit 0 |
Cuándo es seguro
restic unlock por defecto solo borra locks obsoletos, no los de procesos vivos. En esta prueba el lock era de la misma máquina y el PID ya no existía, así que restic lo consideró obsoleto. Antes de ejecutarlo, comprueba con restic list locks y restic cat lock <id> el host y el PID; si otra máquina está usando el repositorio, espera. No uses --remove-all salvo que estés seguro de que nada más escribe.
Aviso: si un lock de otra máquina lleva ahí más de 30 minutos sin renovarse, restic también lo trata como obsoleto. Esto no se probó aquí.
En un script desatendido, ejecutar restic unlock antes de forget --prune es razonable si un solo proceso usa el repositorio; con varios, mejor dejar que falle y avisar. Relacionado: códigos de salida de restic y forget y prune.
Script completo
#!/bin/bash
# restic locks after an interrupted backup. Usage: test-restic-unlock.sh WORKDIR
W=$1; rm -rf "$W"; mkdir -p "$W/data"
export RESTIC_PASSWORD=prueba-desechable
R="$W/repo"; restic init -r "$R" >/dev/null
head -c 200M /dev/urandom > "$W/data/big.bin"
echo "== 1) backup interrumpido con kill -9"
restic -r "$R" backup "$W/data" >/dev/null 2>&1 &
P=$!; sleep 1.5; kill -9 $P; wait $P 2>/dev/null
echo "locks en el repositorio: $(ls "$R/locks" | wc -l)"
echo "== 2) lista de locks"; restic -r "$R" list locks | wc -l
echo "== 3) nuevo backup (lock no exclusivo)"; restic -r "$R" backup "$W/data" --quiet; echo "exit=$?"
echo "== 4) forget --prune con lock viejo"; timeout 60 restic -r "$R" forget --keep-last 1 --prune 2>&1 | tail -4; echo "exit=${PIPESTATUS[0]}"
echo "== 5) unlock (solo locks obsoletos)"; restic -r "$R" unlock; echo "exit=$?"
echo "locks tras unlock: $(ls "$R/locks" | wc -l)"