← retour aux snippets

flock: éviter les exécutions concurrentes

Empêcher qu'un script soit lancé en parallèle, avec timeout et section critique protégée.


objectif

Garantir qu’une tâche ne s’exécute qu’une seule fois à la fois (cron, scripts de maintenance), avec échec rapide si déjà en cours.

code minimal

#!/usr/bin/env bash
set -Eeuo pipefail

lock="/tmp/mon_script.lock"
exec 9>"$lock"
flock -n 9 || { echo "déjà en cours"; exit 1; }

# section critique
echo "travail en cours..."
sleep 5
echo "terminé"

utilisation

# attente maximum 10s pour obtenir le verrou
lock="/tmp/backup.lock"
exec 9>"$lock"
flock -w 10 9 || { echo "verrou occupé"; exit 1; }
rsync -a --delete ./src/ ./dest/

# verrouillage autour d'une commande unique (syntaxe -c)
flock -n /tmp/cleanup.lock -c 'git clean -Xdf && git gc --prune=now'

# verrou nominatif par ressource (ex: base)
db="clients"
flock -n "/tmp/reindex.${db}.lock" -c "psql -d ${db} -c 'REINDEX DATABASE ${db};'"

# verrou par dossier (fallback portable quand flock indisponible)
lockd="/tmp/rapport.lock.d"
if mkdir "$lockd" 2>/dev/null; then
  trap 'rmdir "$lockd"' EXIT INT TERM
  ./genere_rapport.sh
else
  echo "déjà en cours"; exit 1
fi

variante(s) utile(s)

# inclure le PID dans le fichier pour le debug (flock se base sur le descripteur)
lock="/tmp/worker.lock"
printf '%s\n' "$$" > "$lock"
exec 9>"$lock"
flock -n 9 || { echo "en cours par PID $(cat "$lock" 2>/dev/null || echo "?")"; exit 1; }
# ... travail ...

# verrou exclusif sur un dossier de cache
flock -n /tmp/cache_sync.lock -c 'rsync -a --delete ./cache/ /mnt/cache/'

# tenter N fois avec backoff
lock="/tmp/task.lock"
exec 9>"$lock"
for i in 1 2 3; do
  if flock -n 9; then break; fi
  sleep $((i*i))
done
flock -n 9 || { echo "verrou indisponible"; exit 1; }

notes

  • placez le fichier de verrouillage sur un filesystem local (évitez NFS).
  • avec flock, il est inutile de supprimer le fichier de lock; le verrou porte sur le descripteur.
  • la variante mkdir fonctionne partout, mais assurez-vous de bien retirer le dossier dans le trap.
  • utilisez des noms de verrous distincts par ressource (ex: /tmp/backup.<nom>.lock) pour éviter les collisions.