Wait for apt lock during deploy on fresh Ubuntu hosts.

Avoid failing Node install when unattended-upgrades holds dpkg; poll up to 10 minutes then retry.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-07-29 21:20:40 +08:00
parent c41122ae71
commit 17ba41923a
3 changed files with 91 additions and 7 deletions
+66 -7
View File
@@ -34,6 +34,64 @@ require_root() {
fi
}
# 等待 apt/dpkg 锁(常见:unattended-upgrades 正在跑)
wait_for_apt_lock() {
local max_wait="${1:-600}"
local waited=0
local lock_frontend="/var/lib/dpkg/lock-frontend"
local lock_dpkg="/var/lib/dpkg/lock"
local lock_lists="/var/lib/apt/lists/lock"
if ! command -v apt-get >/dev/null 2>&1; then
return 0
fi
while true; do
local busy=0
if pgrep -x unattended-upgr >/dev/null 2>&1 \
|| pgrep -x apt-get >/dev/null 2>&1 \
|| pgrep -x apt >/dev/null 2>&1 \
|| pgrep -x dpkg >/dev/null 2>&1; then
busy=1
fi
# fuser 在有进程占用锁文件时返回 0
if command -v fuser >/dev/null 2>&1; then
if fuser "${lock_frontend}" >/dev/null 2>&1 \
|| fuser "${lock_dpkg}" >/dev/null 2>&1 \
|| fuser "${lock_lists}" >/dev/null 2>&1; then
busy=1
fi
fi
if [[ "${busy}" -eq 0 ]]; then
if [[ "${waited}" -gt 0 ]]; then
log "apt 锁已释放,继续安装"
fi
return 0
fi
if [[ "${waited}" -eq 0 ]]; then
log "检测到 apt/dpkg 正被占用(多为 unattended-upgrades),等待释放…"
log "可另开终端查看: ps aux | grep -E 'unattended|apt|dpkg'"
elif [[ $((waited % 60)) -eq 0 ]]; then
log "仍在等待 apt 锁…已等 ${waited}s / ${max_wait}s"
fi
if [[ "${waited}" -ge "${max_wait}" ]]; then
die "等待 apt 锁超时(${max_wait}s)。请稍后再跑一键部署,或手动: kill 结束后再执行 manage.sh"
fi
sleep 5
waited=$((waited + 5))
done
}
apt_update() {
wait_for_apt_lock
apt-get update -qq
}
apt_install() {
wait_for_apt_lock
apt-get install -y "$@"
}
detect_server_ip() {
local ip=""
if command -v hostname >/dev/null 2>&1; then
@@ -128,8 +186,8 @@ install_python_runtime() {
if ! command -v apt-get >/dev/null 2>&1; then
die "非 apt 系统,请手动安装 python3 python3-venv python3-pip"
fi
apt-get update -qq
apt-get install -y python3 python3-venv python3-pip
apt_update
apt_install python3 python3-venv python3-pip
if ! python_runtime_ok; then
die "Python 环境安装后仍不可用,请检查 apt 源"
fi
@@ -142,10 +200,11 @@ install_node_runtime() {
if ! command -v apt-get >/dev/null 2>&1; then
die "非 apt 系统,请手动安装 Node.js ${NODE_MAJOR}+"
fi
apt-get update -qq
apt-get install -y ca-certificates curl
apt_update
apt_install ca-certificates curl
wait_for_apt_lock
curl -fsSL "https://deb.nodesource.com/setup_${NODE_MAJOR}.x" | bash -
apt-get install -y nodejs
apt_install nodejs
if ! node_runtime_ok; then
die "Node.js 安装后仍不可用"
fi
@@ -177,8 +236,8 @@ ensure_base_packages() {
fi
step "安装基础包: ${need[*]}"
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get install -y ca-certificates "${need[@]}"
apt_update
apt_install ca-certificates "${need[@]}"
}
ensure_system_deps() {
+17
View File
@@ -42,6 +42,23 @@ ensure_git_cli() {
fi
if command -v apt-get >/dev/null 2>&1; then
export DEBIAN_FRONTEND=noninteractive
# 新机常撞 unattended-upgrades 占锁;最多等 10 分钟
local waited=0
while pgrep -x unattended-upgr >/dev/null 2>&1 \
|| pgrep -x apt-get >/dev/null 2>&1 \
|| pgrep -x apt >/dev/null 2>&1 \
|| pgrep -x dpkg >/dev/null 2>&1 \
|| { command -v fuser >/dev/null 2>&1 && fuser /var/lib/dpkg/lock-frontend >/dev/null 2>&1; }; do
if [[ "${waited}" -eq 0 ]]; then
echo "等待 apt 锁释放(unattended-upgrades)…"
fi
if [[ "${waited}" -ge 600 ]]; then
echo "错误: 等待 apt 锁超时,请稍后再试" >&2
exit 1
fi
sleep 5
waited=$((waited + 5))
done
apt-get update -qq
apt-get install -y git ca-certificates curl
else
+8
View File
@@ -5,6 +5,14 @@
---
## 2026-07-29 — 部署:等待 apt 锁(unattended-upgrades
### 变更
1. 一键部署装 Node/系统包前等待 `dpkg`/`apt` 锁释放,避免新机撞上自动升级报错退出。
---
## 2026-07-29 — 文档:云服务器配置选择说明
### 变更