diff --git a/packages/mosaic/framework/tools/wake/detector.sh b/packages/mosaic/framework/tools/wake/detector.sh index 2c064eaa..7f1ddf45 100755 --- a/packages/mosaic/framework/tools/wake/detector.sh +++ b/packages/mosaic/framework/tools/wake/detector.sh @@ -529,7 +529,19 @@ cmd_run() { echo "detector.sh: WARN — off-host liveness beacon emit failed (see beacon.sh); the off-host absence check remains the authoritative dead-man." >&2 fi [ "$once" -eq 1 ] && break - sleep "$interval" + # Close the detector lock fd in the sleep child; otherwise an orphaned sleep + # keeps the single-instance flock (fd 9, taken at exec 9> above) alive after + # the detector parent dies. The lock is non-blocking (`flock -n`, above), so + # for as long as that sleep survives a replacement instance is REFUSED and + # exits rather than queueing. This particular hold is BOUNDED by one poll + # interval (WAKE_DETECTOR_INTERVAL, default 30s): when the orphaned sleep + # exits its copy of fd 9 closes, ending this bounded sleep-child hold. It + # does NOT follow that the next start succeeds — other inheritors of fd 9 + # (the M1 adapter, M2 sink grandchildren) are outside this patch's scope and + # can keep holding the flock. The cost this removes is a restart window in + # which every supervisor retry fails on the sleep child's account. + # `9>&-` closes ONLY the child's copy — the parent's lock is unaffected. + sleep "$interval" 9>&- done }