From 9ec0cacf45733bc8ff78601f75a7e7406e60a0c8 Mon Sep 17 00:00:00 2001 From: dekun Date: Wed, 29 Jul 2026 21:29:38 +0800 Subject: [PATCH] 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 --- deploy/lib/common.sh | 47 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/deploy/lib/common.sh b/deploy/lib/common.sh index 81b5399..05b9b58 100755 --- a/deploy/lib/common.sh +++ b/deploy/lib/common.sh @@ -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))