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:
+66
-7
@@ -34,6 +34,64 @@ require_root() {
|
|||||||
fi
|
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() {
|
detect_server_ip() {
|
||||||
local ip=""
|
local ip=""
|
||||||
if command -v hostname >/dev/null 2>&1; then
|
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
|
if ! command -v apt-get >/dev/null 2>&1; then
|
||||||
die "非 apt 系统,请手动安装 python3 python3-venv python3-pip"
|
die "非 apt 系统,请手动安装 python3 python3-venv python3-pip"
|
||||||
fi
|
fi
|
||||||
apt-get update -qq
|
apt_update
|
||||||
apt-get install -y python3 python3-venv python3-pip
|
apt_install python3 python3-venv python3-pip
|
||||||
if ! python_runtime_ok; then
|
if ! python_runtime_ok; then
|
||||||
die "Python 环境安装后仍不可用,请检查 apt 源"
|
die "Python 环境安装后仍不可用,请检查 apt 源"
|
||||||
fi
|
fi
|
||||||
@@ -142,10 +200,11 @@ install_node_runtime() {
|
|||||||
if ! command -v apt-get >/dev/null 2>&1; then
|
if ! command -v apt-get >/dev/null 2>&1; then
|
||||||
die "非 apt 系统,请手动安装 Node.js ${NODE_MAJOR}+"
|
die "非 apt 系统,请手动安装 Node.js ${NODE_MAJOR}+"
|
||||||
fi
|
fi
|
||||||
apt-get update -qq
|
apt_update
|
||||||
apt-get install -y ca-certificates curl
|
apt_install ca-certificates curl
|
||||||
|
wait_for_apt_lock
|
||||||
curl -fsSL "https://deb.nodesource.com/setup_${NODE_MAJOR}.x" | bash -
|
curl -fsSL "https://deb.nodesource.com/setup_${NODE_MAJOR}.x" | bash -
|
||||||
apt-get install -y nodejs
|
apt_install nodejs
|
||||||
if ! node_runtime_ok; then
|
if ! node_runtime_ok; then
|
||||||
die "Node.js 安装后仍不可用"
|
die "Node.js 安装后仍不可用"
|
||||||
fi
|
fi
|
||||||
@@ -177,8 +236,8 @@ ensure_base_packages() {
|
|||||||
fi
|
fi
|
||||||
step "安装基础包: ${need[*]}"
|
step "安装基础包: ${need[*]}"
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
export DEBIAN_FRONTEND=noninteractive
|
||||||
apt-get update -qq
|
apt_update
|
||||||
apt-get install -y ca-certificates "${need[@]}"
|
apt_install ca-certificates "${need[@]}"
|
||||||
}
|
}
|
||||||
|
|
||||||
ensure_system_deps() {
|
ensure_system_deps() {
|
||||||
|
|||||||
@@ -42,6 +42,23 @@ ensure_git_cli() {
|
|||||||
fi
|
fi
|
||||||
if command -v apt-get >/dev/null 2>&1; then
|
if command -v apt-get >/dev/null 2>&1; then
|
||||||
export DEBIAN_FRONTEND=noninteractive
|
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 update -qq
|
||||||
apt-get install -y git ca-certificates curl
|
apt-get install -y git ca-certificates curl
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -5,6 +5,14 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## 2026-07-29 — 部署:等待 apt 锁(unattended-upgrades)
|
||||||
|
|
||||||
|
### 变更
|
||||||
|
|
||||||
|
1. 一键部署装 Node/系统包前等待 `dpkg`/`apt` 锁释放,避免新机撞上自动升级报错退出。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 2026-07-29 — 文档:云服务器配置选择说明
|
## 2026-07-29 — 文档:云服务器配置选择说明
|
||||||
|
|
||||||
### 变更
|
### 变更
|
||||||
|
|||||||
Reference in New Issue
Block a user