fix(deploy): flock 没登记进 AGENTMAIL_REQUIRE("缺命令"被报成"另一个部署在跑")+ 中断 trap + 两条欠账入册
**1. 自指缺口:新能力带的新依赖没登记回表(pi 抓到)**
我加"同时性"那一列时引入了 `flock`,**却没把 `flock` 加进三个脚本的 `AGENTMAIL_REQUIRE`**。
后果实测:
PATH 里没有 flock ⇒ `flock: command not found`(127)⇒ `! flock` 为真
⇒ 打印"**另一个部署正在跑(锁被占用)**"
退出码事后是对的(2),但**诊断是错的** —— 而照着它做的是"等另一个部署结束":**永远等不到**。
三个脚本各加一个词;并在 `env-defaults.sh` 的 ③b 注释里写明这条规矩
(**新增任何外部命令时回到 `AGENTMAIL_REQUIRE` 登记**)与这个实例。
→ docs 第 19 条:「表与被表的东西不同步」。
**2. 第六列候选:中断(信号)—— 已按 pi 的建议修 `redeploy-gateway.sh`**
原子 `mv` 修的是"半截二进制",**没修"服务停着而脚本死了"**:
第 250 行 stop 与第 267 行 start 之间被外部信号打断(Ctrl-C、宿主杀进程、会话回收、OOM)
⇒ 脚本直接退出、**服务留在停止状态而什么也不说** ⇒ "邮件全停 + 无人告知"。
已加 `trap … INT TERM HUP`:进窗口前置位 `_SERVICE_STOPPED`,出窗口复位并摘 trap;
**trap 只在"确实还停着"时才动手**(否则会多起一次服务);回滚分支也维护该标志。
**用 stub `systemctl` + 探针真喂过四个分支**:
stopped=1 + SIGINT ⇒ 调了 `systemctl start`、退出码 130、打印点名
stopped=0 + SIGINT ⇒ **没有**调用 start(不误起)
(探针里两次 harness 自身的错也一并记下:`sed`/`awk` 的区间端点选错,
把 `trap -` 也取进来,导致"trap 没生效"的假象 —— 是探针错,不是代码错。)
★ 顺带修掉自己写的一处:`printf '… $SERVICE …'` 用**单引号**包裹 ⇒ `$SERVICE` **不展开**,
原样打出字面量(探针里实测看到)。改双引号传参。这类"消息里有变量但没展开"会让读者
以为服务名真叫 `$SERVICE`。
**3. `install -d -m` 对已存在目录的行为:实测会改(pi 的疑问)**
mkdir -p 建 755 → `install -d -m 0700 <同一目录>` → **700**
所以**下一次部署就会收紧** `/opt/agentmail/data` 与 `/etc/agentmail`,不需要额外的
`chmod 0700` 动作,也不必为此单开一次"人按一下"。
(我按这条如实回报,因为 pi 说过"若不会改就需要显式 chmod,且安全意义比
`user-question.js` 高" —— 结论是不需要。)
**4. 两条欠账入 `docs/DEBTS.json`(按 pi 的界线:只修新机制自己引入且会误报的缺口)**
· `deploy-space-prefix-fs`:空间列只铺了 `$TMPDIR`,没铺 `$PREFIX` 所在文件系统
(属"列内没铺满",不是新列)。
· `deploy-interrupt-trap-other-scripts`:trap 只在 `redeploy-gateway.sh`;
`install.sh`/`redeploy-plugin.sh` 被打断同样会留半成品(没有"服务停着"那种后果,故低优先)。
→ docs 第 20 条同时记下 trap 这条纪律与它的可喂判据写法。
验证:install.sh --check exit 0;npm test exit 0;prune 自检 22/22;drift 自检 35/0;
check-shared-libs exit 0;全部 deploy 脚本 bash -n 通过;DEBTS.json 有效(13 条)。
This commit is contained in:
@ -84,6 +84,20 @@
|
||||
"kind": "scope",
|
||||
"due": "**下一次改 `deploy/` 下任一脚本时**必须一并堵(`redeploy-gateway.sh` 正在被另一条会话改 ⇒ 本条目就是给它接手时的入口)。堵法:给每个副作用步骤加 `|| { bad …; exit 2; }`,或在脚本上开 `set -e`;两者都要与既有的 2=环境 / 1=检查 约定对齐。",
|
||||
"where": "`deploy/redeploy-gateway.sh:84` 的 `run \"cp -r '$REPO/client/electron/dist/.' ...\"` —— 脚本只有 `set -uo pipefail`(**无 `-e`**),`run()` 内部 `eval` 的失败既不中断也不被调用点接收 ⇒ 前端产物没拷进去也继续往下走。同类已在 `deploy/redeploy-plugin.sh` 修掉(2026-09-14):那次的实测形状是 `mkdir`/`cp` 被拒后仍打出 `[ OK ] 已拷入 node_modules`,再打出 `[FAIL] staging 里没有入口` —— **一段输出里两个矛盾信号,且 OK 在前**。该文件现已在 `mkdir`/`cp`/`node_modules` 三处判失败并 exit 2。"
|
||||
},
|
||||
{
|
||||
"id": "deploy-space-prefix-fs",
|
||||
"count": 1,
|
||||
"kind": "判据铺得不满(不是新列)",
|
||||
"due": "下一次因空间问题失败时;或有人愿意补一行 df 时",
|
||||
"where": "deploy/lib/env-defaults.sh ②b 只判了 $TMPDIR,没判 $PREFIX 所在的文件系统"
|
||||
},
|
||||
{
|
||||
"id": "deploy-interrupt-trap-other-scripts",
|
||||
"count": 1,
|
||||
"kind": "只在 redeploy-gateway.sh 做了,另两个部署脚本没做",
|
||||
"due": "下一次动 redeploy-plugin.sh / install.sh 时",
|
||||
"where": "只有 redeploy-gateway.sh 有 INT/TERM/HUP trap;install.sh 与 redeploy-plugin.sh 在写系统目录期间被打断同样会留半成品(它们没有\"服务停着\"那种后果,所以优先级低)"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -253,7 +253,22 @@ bash deploy/prune-deploy-artifacts.sh --self-check # 判据自检(16 项,
|
||||
`bad: command not found`(127);`redeploy-plugin.sh` 没有 `$PREFIX`(它用 `$DEST_ROOT`)⇒
|
||||
`PREFIX: unbound variable`(`set -u`);而 `install.sh` 的 `--check` 刻意允许无写权限运行
|
||||
⇒ 在那里建锁又变成 `Permission denied`。三处都是"复制粘贴的上下文假设"。
|
||||
19. **注释里的数字无法被判据守住。** —— 而不是只落到你想到的那一个。**
|
||||
19. **新能力自带的新依赖,要回到那张登记表 —— 否则"表"与"被表的东西"不同步。**
|
||||
实例(pi 评审 2026-09-14):我刚给部署加了"同时性"那一列(`flock` 部署锁),
|
||||
**却忘了把 `flock` 登记进三个脚本的 `AGENTMAIL_REQUIRE`**。后果(已实测):
|
||||
`flock` 不在机器上 ⇒ `command not found`(127)⇒ `! flock` 为真 ⇒
|
||||
打印"**另一个部署正在跑(锁被占用)**" —— 退出码事后是对的(2),
|
||||
但**诊断是错的**,而照着它做的是"等另一个部署结束":**永远等不到**。
|
||||
⇒ 每次给部署路径加一个新命令,都要回去在 `AGENTMAIL_REQUIRE` 里加一个词。
|
||||
20. **"服务停着而脚本死了"是独立于"文件半截"的一类风险 —— 环境前提的第六列候选(中断)。**
|
||||
`redeploy-gateway.sh` 在 `systemctl stop` 与 `systemctl start` 之间有窗口,
|
||||
外部信号(Ctrl-C、宿主杀进程、会话被回收、OOM)会让脚本直接退出 ⇒
|
||||
**服务留在停止状态而脚本什么都不说** ⇒ 后果是"邮件全停 + 无人告知",
|
||||
比半截二进制更难发现。原子 `mv` 只修了后者。
|
||||
修法:进窗口前 `trap … INT TERM HUP`、出窗口摘掉,trap 只在"确实还停着"时动手
|
||||
(否则会多起一次服务)。判据可喂:用 stub `systemctl` + 探针脚本,给自己发 `SIGINT`,
|
||||
断言"停着 ⇒ 调了 start、退出码 130"与"没停 ⇒ 不调 start"。
|
||||
21. **注释里的数字无法被判据守住。** —— 而不是只落到你想到的那一个。**
|
||||
实例(pi 评审 2026-09-14):我在 `env-defaults.sh` 的 `HOME` 上写了两条规则
|
||||
("`mkdir -p` 对已存在的不可写目录会返回成功 ⇒ 必须单独判 `-w`"、"判据落在能不能写、
|
||||
不落在路径像不像"),**同一条规则没落到紧邻的 `TMPDIR` 上** —— 而 ENOSPC 正是这条链的
|
||||
|
||||
Reference in New Issue
Block a user