fix(common): lock registry prevents EXIT trap overwrite orphaning locks
Scripts calling acquire_lock followed by acquire_rsync_lock (rsync.sh) or a custom EXIT trap (resource_watchdog.sh) would overwrite the lock release trap, leaving the first lock file behind on exit. Replace per-acquire trap with a _LOCK_FILES registry. _register_lock() appends each lock file to the array and sets a single _release_all_locks trap. All acquired locks release together on exit regardless of how many traps are subsequently set or overwritten. resource_watchdog.sh: chain _release_all_locks into both its custom trap and the state-persisted disarm path so the lock releases in all exit paths.
This commit is contained in:
@@ -151,7 +151,7 @@ _rw_trap_restart_stopped() {
|
|||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
}
|
}
|
||||||
trap _rw_trap_restart_stopped EXIT
|
trap "_release_all_locks; _rw_trap_restart_stopped" EXIT
|
||||||
|
|
||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
# ━━━ State Helpers ━━━
|
# ━━━ State Helpers ━━━
|
||||||
@@ -580,6 +580,6 @@ fi
|
|||||||
# ==============================================================================================
|
# ==============================================================================================
|
||||||
rm_state_set "rm_paused_containers" "$PAUSED_LIST"
|
rm_state_set "rm_paused_containers" "$PAUSED_LIST"
|
||||||
rm_state_set "rm_stopped_containers" "$STOPPED_LIST"
|
rm_state_set "rm_stopped_containers" "$STOPPED_LIST"
|
||||||
trap - EXIT # state persisted — stopped containers recorded, trap no longer needed
|
trap "_release_all_locks" EXIT # state persisted — disable restart trap, keep lock cleanup
|
||||||
# Touch state file each run so docker_watchdog stale guard sees fresh mtime
|
# Touch state file each run so docker_watchdog stale guard sees fresh mtime
|
||||||
touch "$RW_STATE_FILE" 2>/dev/null
|
touch "$RW_STATE_FILE" 2>/dev/null
|
||||||
|
|||||||
@@ -1253,6 +1253,21 @@ RSYNC_MAX_CONCURRENT=3
|
|||||||
LOCK_WARN_AGE=300 # seconds — warn if lock older than this (5min default)
|
LOCK_WARN_AGE=300 # seconds — warn if lock older than this (5min default)
|
||||||
LOCK_WAIT_TIMEOUT=30 # seconds — how long "wait" mode waits before giving up
|
LOCK_WAIT_TIMEOUT=30 # seconds — how long "wait" mode waits before giving up
|
||||||
|
|
||||||
|
# Registry of all lock files acquired by this process — released together on exit.
|
||||||
|
# Prevents the single-trap-per-acquire problem: each new acquire_lock/acquire_rsync_lock
|
||||||
|
# call used to overwrite the EXIT trap, orphaning the previous lock file.
|
||||||
|
declare -ga _LOCK_FILES=()
|
||||||
|
_release_all_locks() {
|
||||||
|
local lf
|
||||||
|
for lf in "${_LOCK_FILES[@]}"; do
|
||||||
|
[[ -f "$lf" ]] && rm -f "$lf"
|
||||||
|
done
|
||||||
|
}
|
||||||
|
_register_lock() {
|
||||||
|
_LOCK_FILES+=("$1")
|
||||||
|
trap '_release_all_locks' EXIT
|
||||||
|
}
|
||||||
|
|
||||||
# Internal — script name used as lock identifier
|
# Internal — script name used as lock identifier
|
||||||
_lock_name() {
|
_lock_name() {
|
||||||
basename "${BASH_SOURCE[1]:-$0}" .sh
|
basename "${BASH_SOURCE[1]:-$0}" .sh
|
||||||
@@ -1344,7 +1359,7 @@ acquire_lock() {
|
|||||||
|
|
||||||
# Acquire lock — store PID:scriptname to prevent PID reuse false positives
|
# Acquire lock — store PID:scriptname to prevent PID reuse false positives
|
||||||
echo "$$:$script_name" > "$lockfile"
|
echo "$$:$script_name" > "$lockfile"
|
||||||
trap "_release_on_exit '$lockfile'" EXIT
|
_register_lock "$lockfile"
|
||||||
log "$ICON_LOCK Lock acquired: $script_name (PID $$)"
|
log "$ICON_LOCK Lock acquired: $script_name (PID $$)"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1402,7 +1417,7 @@ acquire_rsync_lock() {
|
|||||||
# Acquire profile lock and increment counter
|
# Acquire profile lock and increment counter
|
||||||
echo "$$:rsync_${profile}" > "$profile_lock"
|
echo "$$:rsync_${profile}" > "$profile_lock"
|
||||||
echo $(( current_count + 1 )) > "$RSYNC_COUNT_FILE"
|
echo $(( current_count + 1 )) > "$RSYNC_COUNT_FILE"
|
||||||
trap "_release_rsync_on_exit '$profile_lock'" EXIT
|
_register_lock "$profile_lock"
|
||||||
log "$ICON_LOCK rsync lock acquired: profile '$profile' (PID $$, active: $(( current_count + 1 ))/$RSYNC_MAX_CONCURRENT)"
|
log "$ICON_LOCK rsync lock acquired: profile '$profile' (PID $$, active: $(( current_count + 1 ))/$RSYNC_MAX_CONCURRENT)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user