Files
MailUI4Agents/deploy/prune-deploy-artifacts.sh
JianFeeeee 69b1887eae chore(deploy): 清理部署残留(1.0GB)+ 把清理写成可复跑脚本
用户说「清理一下」。实测 /opt/agentmail 累计 1.3GB:
- 网关旧二进制 33 份 × 24MB ≈ 790MB(每次 redeploy 留一份,从 09-05 起没清过)
- 插件快照:opencode 6 份 339MB、dsh 7 份 195MB、zcode 16 份、pi 9 份
- /tmp 里的部署前数据库备份 10 份(tmpfs,占内存)

新增 `deploy/prune-deploy-artifacts.sh`(可复跑,不手敲 rm),两条硬规矩:
① **保留回滚窗口**:网关留最新 3 份、每个插件留最新 3 份快照,`current` 永远保留
(发布纪律要求有回滚目标,所以不是全清);
② ★ **绝不删正在使用的快照**:扫 /proc 的 cmdline 与 cwd,命中就跳过。

执行结果:**/opt/agentmail 1305MB → 302MB(释放 1003MB)**,7 个服务全部 active,
`current` 指向未变,`check-deploy-drift` 仍报「四个宿主都在跑当前代码」。

## 过程中的一处自纠

"在用"闸门第一版有**自我匹配**缺陷:我的测试命令把路径写在命令行里,于是扫 /proc 时
扫到了自己 ⇒ 对不存在的路径也判"在用"(与 `pkill -f` 杀掉自己那条命令同一类)。
已改为排除本进程及其祖先链,并**换正确方式重测**(路径从文件读、不进 cmdline):
在用快照判"在用" ✓、不存在的路径不误判 ✓ —— 判据两侧都验过才敢执行删除。

文档:docs/DEV-TOOLING.md 记了用法与那两条规矩。
2026-09-14 08:43:54 +08:00

108 lines
4.4 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
# 清理部署残留:旧网关二进制、旧插件快照、/tmp 里的部署前数据库备份。
#
# # 为什么要脚本而不是手敲 rm
#
# 这些东西**天天在长**:每次 redeploy 留一个 24MB 的网关二进制、每个插件留一份快照
# opencode/dsh 的快照含 node_modules一份几十 MB。2026-09-14 实测:
# /opt/agentmail 1.3G,其中旧二进制 ~790MB、插件快照 ~540MB。
# 手敲的清理不可复现、下次还得再想一遍,而且很容易漏掉"这一份还在被用"的判断。
#
# # 两条硬规矩
#
# ① **保留回滚窗口**:网关二进制留最新 N 份、每个插件留最新 N 份快照
# `current` 永远保留)。发布纪律要求"有回滚目标",所以不是全清。
# ② ★ **绝不删正在使用的快照**:任何进程的 cmdline 里出现过的快照路径一律跳过。
# 删掉它 = 进程一重启就找不到自己的代码(而这类事故此前真发生过)。
#
# 用法:
# bash deploy/prune-deploy-artifacts.sh # 干跑,只报告
# bash deploy/prune-deploy-artifacts.sh --apply # 真删
# KEEP_GATEWAY=2 KEEP_SNAPSHOTS=2 bash ... --apply # 调保留窗口
set -uo pipefail
ROOT="${AGENTMAIL_ROOT:-/opt/agentmail}"
KEEP_GATEWAY="${KEEP_GATEWAY:-3}"
KEEP_SNAPSHOTS="${KEEP_SNAPSHOTS:-3}"
KEEP_TMP_DB="${KEEP_TMP_DB:-2}"
APPLY=0
[ "${1:-}" = "--apply" ] && APPLY=1
freed_kb=0
removed=0
skipped=0
report() { printf ' %s %s\n' "$1" "$2"; }
# 收集所有"正在被进程使用"的路径cmdline + cwd用来做安全闸。
# 自己这条命令的 cmdline 里就可能含这个路径(例如调用方把路径写在命令行里),
# 于是"检查在用"会永远为真 —— 与 `pkill -f` 杀掉自己那条命令是同一个坑。
# 所以先把本进程及其祖先链排除掉。
_SELF_CHAIN=" "
_p=$$
while [ -n "$_p" ] && [ "$_p" != "1" ] && [ "$_p" != "0" ]; do
_SELF_CHAIN="$_SELF_CHAIN$_p "
_p=$(awk '{print $4}' "/proc/$_p/stat" 2>/dev/null || echo "")
done
in_use() {
local needle="$1" p pid
for p in /proc/[0-9]*; do
pid=${p#/proc/}
[ -r "$p/cmdline" ] || continue
case "$_SELF_CHAIN" in *" $pid "*) continue;; esac
if tr '\0' ' ' <"$p/cmdline" 2>/dev/null | grep -qF "$needle"; then return 0; fi
local cwd; cwd=$(readlink "$p/cwd" 2>/dev/null || true)
case "$cwd" in *"$needle"*) return 0;; esac
done
return 1
}
del() {
local path="$1"
local kb; kb=$(du -sk "$path" 2>/dev/null | cut -f1); kb=${kb:-0}
if [ "$APPLY" = "1" ]; then rm -rf "$path"; fi
freed_kb=$((freed_kb + kb)); removed=$((removed + 1))
report " $([ "$APPLY" = 1 ] && echo 删除 || echo 待删)" "$path$((kb/1024))MB"
}
echo "==> 网关旧二进制(保留最新 $KEEP_GATEWAY 份)"
mapfile -t bins < <(ls -1t "$ROOT"/agentmail-gateway.bak-* 2>/dev/null)
for i in "${!bins[@]}"; do
[ "$i" -lt "$KEEP_GATEWAY" ] && { report " 保留" "${bins[$i]}"; continue; }
if in_use "${bins[$i]}"; then report " ★跳过(正在被使用)" "${bins[$i]}"; skipped=$((skipped+1)); continue; fi
del "${bins[$i]}"
done
echo "==> 插件快照(每个插件保留最新 $KEEP_SNAPSHOTScurrent 永远保留)"
for plug in "$ROOT"/plugins/*/; do
[ -d "$plug" ] || continue
name=$(basename "$plug")
mapfile -t snaps < <(ls -1dt "$plug"*/ 2>/dev/null | sed 's:/$::')
for i in "${!snaps[@]}"; do
s="${snaps[$i]}"
[ "$(basename "$s")" = "current" ] && continue
# current 指向的那一份也必须保留
cur=$(readlink -f "$plug/current" 2>/dev/null || true)
[ "$cur" = "$(readlink -f "$s")" ] && { report " 保留" "$scurrent 指向)"; continue; }
if [ "$i" -lt "$KEEP_SNAPSHOTS" ]; then report " 保留" "$s"; continue; fi
if in_use "$s"; then report " ★跳过(正在被使用)" "$s"; skipped=$((skipped+1)); continue; fi
del "$s"
done
done
echo "==> /tmp 的部署前数据库备份(保留最新 $KEEP_TMP_DB 份)"
mapfile -t dbs < <(ls -1t /tmp/agentmail-pre-deploy-*.db 2>/dev/null)
for i in "${!dbs[@]}"; do
[ "$i" -lt "$KEEP_TMP_DB" ] && { report " 保留" "${dbs[$i]}"; continue; }
del "${dbs[$i]}"
done
echo
if [ "$APPLY" = "1" ]; then
echo " 已删除 $removed 项,释放约 $((freed_kb/1024))MB跳过在用$skipped"
else
echo " 干跑:将删除 $removed 项,可释放约 $((freed_kb/1024))MB跳过在用$skipped"
echo " 加 --apply 执行。"
fi