Improve apt-lock wait: stop unattended-upgrades during deploy.
Shows lock holders and optionally stops auto-upgrade so Node install is not stuck after reboot. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+44
-3
@@ -34,6 +34,37 @@ require_root() {
|
||||
fi
|
||||
}
|
||||
|
||||
# 打印当前占用 apt 的进程,便于排查
|
||||
_apt_lock_holders() {
|
||||
ps -eo pid,cmd 2>/dev/null | grep -E '[u]nattended-upgr|[a]pt-get|[a]pt |[d]pkg ' | head -n 8 || true
|
||||
if command -v fuser >/dev/null 2>&1; then
|
||||
fuser -v /var/lib/dpkg/lock-frontend /var/lib/dpkg/lock /var/lib/apt/lists/lock 2>&1 | head -n 12 || true
|
||||
fi
|
||||
}
|
||||
|
||||
# 部署期间临时停自动升级(重启后常立刻再跑,占锁很久)
|
||||
_stop_auto_apt_for_deploy() {
|
||||
if [[ "${APT_STOP_AUTO:-1}" != "1" ]]; then
|
||||
return 0
|
||||
fi
|
||||
if command -v systemctl >/dev/null 2>&1; then
|
||||
log "临时停止 unattended-upgrades / apt-daily,避免占锁…"
|
||||
systemctl stop unattended-upgrades.service 2>/dev/null || true
|
||||
systemctl stop apt-daily.service apt-daily-upgrade.service 2>/dev/null || true
|
||||
systemctl kill --kill-who=all unattended-upgrades.service 2>/dev/null || true
|
||||
fi
|
||||
# 若仍卡死且 APT_FORCE_UNLOCK=1,才强杀(默认不杀,避免打断半截升级)
|
||||
if [[ "${APT_FORCE_UNLOCK:-0}" == "1" ]]; then
|
||||
log "APT_FORCE_UNLOCK=1:结束残留 apt/dpkg 进程…"
|
||||
pkill -9 -x unattended-upgr 2>/dev/null || true
|
||||
pkill -9 -x apt-get 2>/dev/null || true
|
||||
pkill -9 -x apt 2>/dev/null || true
|
||||
pkill -9 -x dpkg 2>/dev/null || true
|
||||
sleep 2
|
||||
dpkg --configure -a 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
# 等待 apt/dpkg 锁(常见:unattended-upgrades 正在跑)
|
||||
wait_for_apt_lock() {
|
||||
local max_wait="${1:-600}"
|
||||
@@ -41,6 +72,7 @@ wait_for_apt_lock() {
|
||||
local lock_frontend="/var/lib/dpkg/lock-frontend"
|
||||
local lock_dpkg="/var/lib/dpkg/lock"
|
||||
local lock_lists="/var/lib/apt/lists/lock"
|
||||
local tried_stop=0
|
||||
|
||||
if ! command -v apt-get >/dev/null 2>&1; then
|
||||
return 0
|
||||
@@ -69,13 +101,22 @@ wait_for_apt_lock() {
|
||||
return 0
|
||||
fi
|
||||
if [[ "${waited}" -eq 0 ]]; then
|
||||
log "检测到 apt/dpkg 正被占用(多为 unattended-upgrades),等待释放…"
|
||||
log "可另开终端查看: ps aux | grep -E 'unattended|apt|dpkg'"
|
||||
log "检测到 apt/dpkg 正被占用(多为重启后的 unattended-upgrades),等待释放…"
|
||||
log "占用进程:"
|
||||
_apt_lock_holders | while IFS= read -r line; do log " ${line}"; done
|
||||
log "可另开终端: ps aux | grep -E 'unattended|apt|dpkg'"
|
||||
elif [[ "${tried_stop}" -eq 0 && "${waited}" -ge 15 ]]; then
|
||||
# 等约 15s 仍占用:停自动升级服务(不杀半截 dpkg,除非 APT_FORCE_UNLOCK=1)
|
||||
tried_stop=1
|
||||
_stop_auto_apt_for_deploy
|
||||
elif [[ $((waited % 60)) -eq 0 ]]; then
|
||||
log "仍在等待 apt 锁…已等 ${waited}s / ${max_wait}s"
|
||||
_apt_lock_holders | while IFS= read -r line; do log " ${line}"; done
|
||||
fi
|
||||
if [[ "${waited}" -ge "${max_wait}" ]]; then
|
||||
die "等待 apt 锁超时(${max_wait}s)。请稍后再跑一键部署,或手动: kill 结束后再执行 manage.sh"
|
||||
log "超时前占用进程:"
|
||||
_apt_lock_holders | while IFS= read -r line; do log " ${line}"; done
|
||||
die "等待 apt 锁超时(${max_wait}s)。可手动: systemctl stop unattended-upgrades; 或 APT_FORCE_UNLOCK=1 bash manage.sh"
|
||||
fi
|
||||
sleep 5
|
||||
waited=$((waited + 5))
|
||||
|
||||
Reference in New Issue
Block a user