objectif
Basculer un symlink vers une nouvelle release de manière atomique (opération instantanée), sûre et réversible, sans fenêtre d’indisponibilité.
code minimal
# bascule atomique (même dossier -> même filesystem)
set -Eeuo pipefail
new="/srv/app/releases/2005-08-15_1200"
tmp="current.new"
ln -sfn "$new" "$tmp"
mv -f "$tmp" current
utilisation
# 1) préparer la nouvelle release
new="/srv/app/releases/2005-08-15_1200"
[ -d "$new" ] || { echo "absent: $new" >&2; exit 1; }
# 2) bascule atomique avec sauvegarde de l'ancienne cible (pour rollback)
set -Eeuo pipefail
old="$(readlink current || true)"
tmp="current.new"
ln -sfn "$new" "$tmp"
mv -f "$tmp" current
# 3) vérifier la cible
readlink current
# 4) rollback si nécessaire
if [ -n "${old:-}" ] && [ -e "$old" ]; then
ln -sfn "$old" "$tmp"
mv -f "$tmp" current
fi
variante(s) utile(s)
# Linux (GNU coreutils): utiliser -T pour forcer le renommage de fichier
ln -sfn "$new" current.new && mv -f -T current.new current
# macOS/BSD: sans -T (rename reste atomique si même dossier)
ln -sfn "$new" current.new && mv -f current.new current
# empêcher la bascule si la nouvelle release est incomplète (fichier sentinelle)
[ -f "$new/.ready" ] || { echo "release non prête"; exit 1; }
ln -sfn "$new" current.new && mv -f current.new current
# consigner la bascule (journal simple)
ts="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
printf '%s %s -> %s\n' "$ts" "${old:-none}" "$new" >> deploy.log
# service qui suit le symlink (ex: systemd): recharger sans restart complet
# systemctl reload myapp.service # si applicable
notes
- l’opération
mvdans le même dossier est un renommage atomique: aucune fenêtre où “current” pointe vers rien. - créez le lien temporaire dans le même répertoire que “current” pour garantir l’atomicité (même filesystem).
-sfn: crée un symlink, force le remplacement et traite la cible comme un fichier même si c’est un lien vers un dossier.- gardez la valeur précédente avec
readlinkpour un rollback rapide et traçable.