chore(deploy): 部署漂移检查器 —— 快照是不是还等于仓库、进程到底在跑哪份代码
「部署脚本跑过了」不等于「线上跑的是当前代码」。三种各自独立的漂移,谁都不会
在意,直到出问题时才发现线上是几天前的行为:
1. 仓库改了、快照没重新部署(快照是独立副本)
2. **软链切了、进程没重启** —— `current` 只是个符号链接,切换它不会重载
已在跑的进程,进程持有的是启动那一刻加载进内存的代码
3. 单元/配置改了、没 daemon-reload 或没重装
`node deploy/check-deploy-drift.mjs`(`--self-check` / `--json`)把三件事变成
可判定的:逐字节比内容(**不用 diff** —— 本机 PATH 上那个是鸿蒙工具链里的,
对内容不同的文件仍返回 0)、读进程真实 argv、比进程启动时刻与软链切换时刻。
## 判据必须按宿主真实的加载方式分开写(这是踩出来的)
第一版对四个宿主用同一套判据(「单元 ExecStart 指向 current」+「进程 argv 里有
快照路径」),结果 **opencode 与 dsh 双双假红**:它们的插件由**宿主进程**加载,
argv 里永远只有宿主自己的可执行文件。永假条件在检查器里表现为「稳定的红灯」,
人会学会忽略它。
| 宿主 | 谁加载 | 从哪里读 | 切换后要重启吗 |
|---|---|---|---|
| pi / zcode | 自己的进程 | unit 的 ExecStart | 要(启动时加载) |
| dsh | dsh 宿主 | profile `link:` → `node_modules` 软链 | 要(服务启动时) |
| opencode | opencode 宿主 | `opencode.jsonc` 的 `plugin:` | 不要(会话创建时惰加载) |
## 判据自检也修了一次
第一版自检「宿主表:运行时加载的宿主必须标记需要重启」写的是
`h.restartOnSwitch !== false`,而 `undefined` 也被放过 —— 于是 pi/zcode 的
`restartOnSwitch` 缺省成 undefined、落进「惰加载」分支、判据**永真**。
现在这条判据抽成纯函数 `judgeRestart`,自检用**行为用例**盖住:
旧进程 + 启动时加载的宿主必须判红、惰加载的宿主不判红、切换后启动的一律放行、
读不到启动时刻时不据此判红、容差内不判红。
## 扰动实验(在真实对象上证明判据会红)
- 改一个仓库运行文件 → pi 的「① 运行文件与仓库一致」变红,恢复即绿 ✓
- 只把 pi 的软链 mtime 拨到刚刚(模拟「切了没重启」)→ 「④」变红并指出原因 ✓
- 把 dsh 与 opencode 的软链都拨动 → **dsh 红、opencode 绿**(惰加载该保持绿)✓
全部拨动均已在实验后还原并复核为绿。
## 当前结论
四个宿主都在跑当前代码(pi/opencode/dsh 的快照自 11:45 起未变,其间无提交
动过它们的运行文件;zcode 是 18:57 的快照)。「三桥加载规范化」的切换本身
早已完成,缺的是这条可复跑的判据 —— 补齐了。
另外修了 `redeploy-plugin.sh` 的一个静默问题:`usage()` 按**行号范围**截取头部
注释(`sed -n '2,40p'`),我这次的注释把退出码那段挤到 40 行之后,`--help`
就少了半页。已同步范围并就地记下这个陷阱。
This commit is contained in:
@ -27,6 +27,19 @@
|
||||
# → 5 重启 → 6 后置验证(服务 active **且** 桥日志出现「已接入」)
|
||||
# → 任一步失败即切回 .prev 并重启
|
||||
#
|
||||
# # 事后自查:`deploy/check-deploy-drift.mjs`
|
||||
#
|
||||
# 这个脚本管的是「这一刻切没切对」;那份快照**过一段时间之后**是否还等于
|
||||
# 仓库 HEAD、以及进程是否真的在跑那份代码,是另一个问题,需要另一个检查:
|
||||
#
|
||||
# node deploy/check-deploy-drift.mjs # 四个宿主一起看
|
||||
# node deploy/check-deploy-drift.mjs --self-check # 先证明判据能发现差异
|
||||
#
|
||||
# 它把三种**各自独立**的漂移变成可判定的:仓库改了没重部署;软链切了没重启
|
||||
# (`current` 只是个符号链接,切换它**不会**重载已在跑的进程);单元/配置改了
|
||||
# 没 daemon-reload 或没重装。四种宿主的插件加载方式不同,判据也按各自的来
|
||||
# (自有进程看 argv,dsh 看 node_modules 软链,opencode 惰加载不强制重启)。
|
||||
#
|
||||
# 退出码: 0=成功 1=失败或验证不过(已尝试回滚) 2=参数/环境问题
|
||||
#
|
||||
set -uo pipefail
|
||||
@ -37,7 +50,9 @@ DEST_ROOT=${DEST_ROOT:-/opt/agentmail/plugins}
|
||||
STAGE_ONLY=0
|
||||
PLUGIN=""
|
||||
|
||||
usage() { sed -n '2,40p' "$0"; }
|
||||
# 头部注释的**行号范围**用来当 usage:改注释时必须同步上下文,
|
||||
# 否则 `--help` 会默默截断(不报错,只是少一段)——这本身就是个静默漂移。
|
||||
usage() { sed -n '2,44p' "$0"; }
|
||||
|
||||
for arg in "$@"; do
|
||||
case "$arg" in
|
||||
|
||||
Reference in New Issue
Block a user