npm run agc 按 Ctrl+C 会残留上个 worktree 的后端,切换工作树时复用旧后端 #314
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
现象
npm run agc在终端按 Ctrl+C 后,有概率上个工作树的api-server.exe/ SpacetimeDB 仍在监听8082/8083/3101。切到另一个 worktree 再启动 AGC 时,前端仍然连到上个工作树的后端;在改过数据库 / schema 的工作树上会串库,风险很高。根因(三层叠加)
shell: true的cmd.exe /d /s /c包装层启动。Ctrl+C 会先杀掉包装层(退出码0xC000013A),而scripts/dev.mjs的stopProcess()见到直接子进程已退出就直接return;start-dev-stack.mjs/start-tauri-dev.mjs对已退出 PID 执行taskkill /PID <pid> /T /F只会失败(stopped: false)。更深的cargo → api-server.exe没有任何人收。cmd(10) → wrapper(20) → api-server(30),快照只剩 30 时,从 10 遍历结果只有[10]。isBackendReady()只用.app/dev-stack.json的 status 加/healthz、/readyz、/v1/ping,从不校验端口上的进程属于哪个工作树。残留后端照样“健康”,于是被当前工作树当成自己的后端复用。复现步骤
npm run agc,等配套后端就绪;api-server的with_graceful_shutdown没有 deadline,长连接 / 流式请求在飞时更容易拖住退出);Get-CimInstance Win32_Process | Where-Object { $_.Name -eq 'api-server.exe' }仍能看到 A 的server-rs\target\debug\api-server.exe;npm run agc,AGC 直接复用 A 的后端(B 的 Vite 代理指向 A 的8082)。修复方案(已在本地实现,待提交)
scripts/dev-windows-process.mjs:同时提供「按根 PID 遍历」与「按身份匹配」两条独立清理路径(server-rs/target/debug/api-server.exe绝对路径、SpacetimeDB--data-dir),后者不依赖任何存活的包装层;scripts/dev.mjs:直接子进程已退出时也继续清理;退出时按身份兜底清扫本工作树后端(复用他人 standalone 时不清理);apps/ai-game-creator-shell/scripts/start-dev-stack.mjs:复用前校验端口监听进程归属,无法证明归属就不复用,改为启动本工作树自己的后端并允许端口漂移;收到信号与finally各兜底清扫一次本工作树api-server.exe;taskkill失败时降级为按 PID 遍历;docs/project-memory/shared-memory/pitfalls.md与docs/【开发运维】本地开发验证与生产运维-2026-05-15.md。验证
api-server.exe进程:按身份精确命中并杀掉(matched=[17284] stopped=[17284]);owned/api-server-owner-mismatch/spacetime-owner-mismatch均正确;npx vitest run:dev 栈相关套件 1066 passed(唯一失败为 HEAD 上已存在的 Windows 文件权限用例);node --check、eslint --max-warnings 0、prettier --check、npm run check:encoding、git diff --check全部通过。备注
Rust 侧
api-server的优雅退出没有超时上限,是“有概率”的来源之一;本次只在 Node 侧收口。是否给with_graceful_shutdown加 deadline 可以另行评估。