Fix static fresh-start pidcheck so health loop stays alive

Why: write_static_reg omitted pidcheck and pid_alive ignored in-memory
SVC_PIDCHECK, so first-boot curl probes fell back to agent-system and
misread python http.server as exited.
Evidence: python3 -m unittest tests.test_svc -v (17/17, new static case)
Impact: Static --dir deploy survives the pre-record_state health loop.
Refs: fix/svc-static-pidcheck-fresh-start

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-12 08:35:44 +00:00
co-authored by Cursor
parent b04eb0de7e
commit 6056838b48
3 changed files with 89 additions and 19 deletions
File diff suppressed because one or more lines are too long
+8 -2
View File
@@ -860,10 +860,13 @@ pid_alive_mark() { # PID MARKER:cmdline 含 MARKER 视为我们的进程
case "$cmd" in *"$mark"*) return 0 ;; *) return 1 ;; esac
}
# pid_alive PID:当前服务的 pid 校验(svc.env pidcheck 优先;旧登记回退 agent-system)。
# pid_alive PID:当前服务的 pid 校验(内存 SVC_PIDCHECK → svc.env pidcheck → agent-system)。
# 启动路径在 record_state 之前就会调本函数;static 首启若只读 svc.env 会误回退到
# agent-system,把 python http.server 判成「进程即退」。
pid_alive() {
local pid="$1" mark
mark="$(svc_get pidcheck)"
mark="${SVC_PIDCHECK:-}"
[ -z "$mark" ] && mark="$(svc_get pidcheck)"
[ -z "$mark" ] && mark="agent-system"
pid_alive_mark "$pid" "$mark"
}
@@ -2208,11 +2211,13 @@ resolve_dir_deploy() { # --dir 路径:登记(含 dry-run 计划)后交由
}
# write_static_reg HTDOCS:登记/更新 static 服务(保留 pid 等当前态由 start 覆写)。
# 同步写入 pidcheck,避免首启在 record_state 前 pid_alive 误回退到 agent-system。
write_static_reg() {
local htdocs="$1"
local old_pid=""; [ -f "$ENV_PID" ] && old_pid="$(read_pid)"
local merged_tags; merged_tags="$(svc_merge_tags)" # 先读旧文件再截断
mkdir -p "$ENV_DIR"
SVC_PIDCHECK="--directory $htdocs"
{
printf 'kind=static\n'
printf 'env=%s\n' "$ENV_NAME"
@@ -2222,6 +2227,7 @@ write_static_reg() {
printf 'source=%s\n' "$SRC_LABEL"
printf 'started=%s\n' "$(date -Is)"
printf 'htdocs=%s\n' "$htdocs"
printf 'pidcheck=%s\n' "$SVC_PIDCHECK"
} > "$ENV_DIR/svc.env"
chmod 600 "$ENV_DIR/svc.env"
}
+25
View File
@@ -11,6 +11,7 @@ import shutil
import subprocess
import tempfile
import unittest
import urllib.request
from pathlib import Path
SOURCE = Path(__file__).resolve().parents[1]
@@ -741,6 +742,30 @@ class SvcDbRecoveryTests(unittest.TestCase):
self.assertNotEqual(new, old)
self.assertIn("args:", self.serve_record()) # 更新后健康在跑
# ---- static 全新部署:首启健康循环不得误判「进程即退」 ----
def test_static_fresh_deploy_registers_pidcheck_and_starts(self):
"""全新 static --dir:登记须含 pidcheck;首启探活不得把 http.server 判死。"""
htdocs = self.root / "static-site"
htdocs.mkdir()
(htdocs / "index.html").write_text("<html>static-ok</html>\n")
port = 18951
result = self.svc(
"uiqa", "deploy", "--kind", "static",
"--dir", str(htdocs), "--addr", "127.0.0.1:%d" % port)
self.assertIn("已启动", result.stdout)
self.assertNotIn("进程即退", result.stdout)
self.assertEqual(self.kv("uiqa", "kind"), "static")
pidcheck = self.kv("uiqa", "pidcheck")
self.assertIsNotNone(pidcheck)
self.assertIn("--directory", pidcheck)
# write_static_reg 用 cd 后的绝对路径;与 resolve 后的 htdocs 对齐。
self.assertIn(str(htdocs.resolve()), pidcheck)
self.assertTrue(self.pid_alive("uiqa"))
with urllib.request.urlopen("http://127.0.0.1:%d/" % port, timeout=3) as resp:
self.assertEqual(resp.status, 200)
self.assertIn(b"static-ok", resp.read())
if __name__ == "__main__":
unittest.main()