From df32bc8f8245eee79032d7b1444f80bf774fb6b7 Mon Sep 17 00:00:00 2001 From: Erich Blume Date: Mon, 26 Jan 2026 12:34:55 -0800 Subject: [PATCH] Add lockfile to prevent concurrent immich-sync runs - Creates ~/.immich-sync.lock with PID on start - Checks if existing lock's process is still running (stale lock detection) - Logs clear message when skipping due to active lock - Releases lock on exit via trap (handles success and failure) Co-Authored-By: Claude Opus 4.5 --- .../immich_sync/templates/immich-sync.sh.j2 | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/ansible/roles/immich_sync/templates/immich-sync.sh.j2 b/ansible/roles/immich_sync/templates/immich-sync.sh.j2 index 379e3af..1895a12 100644 --- a/ansible/roles/immich_sync/templates/immich-sync.sh.j2 +++ b/ansible/roles/immich_sync/templates/immich-sync.sh.j2 @@ -18,6 +18,7 @@ DOCKER=/usr/local/bin/docker EXPORT_DIR="{{ immich_sync_export_dir }}" IMMICH_URL="{{ immich_sync_url }}" API_KEY_FILE="$HOME/.immich-api-key" +LOCKFILE="$HOME/.immich-sync.lock" LOG_PREFIX="[immich-sync]" log() { @@ -28,6 +29,43 @@ error() { echo "$LOG_PREFIX $(date '+%Y-%m-%d %H:%M:%S') ERROR: $*" >&2 } +# Lockfile management to prevent concurrent runs +acquire_lock() { + if [[ -f "$LOCKFILE" ]]; then + local lock_pid lock_time + lock_pid=$(cat "$LOCKFILE" 2>/dev/null | head -1) + lock_time=$(stat -f %Sm -t '%Y-%m-%d %H:%M:%S' "$LOCKFILE" 2>/dev/null || echo "unknown") + + # Check if the process is still running + if [[ -n "$lock_pid" ]] && kill -0 "$lock_pid" 2>/dev/null; then + error "Another sync is already running (PID: $lock_pid, started: $lock_time)" + error "Lockfile: $LOCKFILE" + error "If this is stale, remove the lockfile manually: rm $LOCKFILE" + exit 0 # Exit cleanly so LaunchAgent doesn't report failure + else + log "WARNING: Found stale lockfile from PID $lock_pid (process not running), removing it" + rm -f "$LOCKFILE" + fi + fi + + # Create lockfile with our PID + echo $$ > "$LOCKFILE" + log "Acquired lock (PID: $$)" +} + +release_lock() { + if [[ -f "$LOCKFILE" ]]; then + rm -f "$LOCKFILE" + log "Released lock" + fi +} + +# Ensure lock is released on exit (success or failure) +trap release_lock EXIT + +# Acquire lock before doing anything else +acquire_lock + # Check prerequisites if [[ ! -x "$MISE" ]]; then error "mise not found at $MISE"