Skip to content

fix(installer): keep hard-kill timer alive until timed-out process groups are terminated #2

Description

@LIghtJUNction

问题

bounded() 在超时后先发送进程组 SIGTERM,再安排三秒后的 SIGKILL,但是随即对强制终止定时器调用 unref()。如果直接子进程已经退出、同组后代仍在运行,Node 包装进程会提前退出,SIGKILL 回调不再执行。

这不是只存在于旧版本的问题:已核查 main 和当前重写 PR #1,两处仍然使用相同逻辑。

位置:

关键代码:

try { process.kill(-child.pid, 'SIGTERM'); } catch {}
const hard = setTimeout(() => {
  try { process.kill(-child.pid, 'SIGKILL'); } catch {}
}, 3000);
hard.unref();
// child exit 时清除 heartbeat 和 timeout,不再有引用维持包装进程。

已执行的离线复现

环境:Linux,Node v22.16.0。仅执行源码中原样提取的 JavaScript 包装函数,不是整套安装器兼容性测试,没有 npm 安装和外部网络请求。

复现步骤:

  1. 使用原 bounded() 的 JS,命令超时设为 1 秒。
  2. 它启动一个模拟构建主进程,主进程再启动同进程组的后代;后代捕获并忽略 SIGTERM,写出 PID 后等待。主进程对 SIGTERM 使用默认退出行为。
  3. 等待包装进程退出,再在启动后 4.5 秒检查后代的 /proc/<pid>/stat,排除僵尸状态。
  4. 对照组只把 hard.unref() 换成 void hard,其余逻辑不变。
  5. 每轮 finally 显式 SIGKILL 测试创建的进程组,避免留下模拟进程。

实际输出:

original:
  exit=124, wrapper_elapsed=1.171s
  worker_running_after_4.5s=True, worker_state=S

referenced-timer-control:
  exit=124, wrapper_elapsed=4.154s
  worker_running_after_4.5s=False, worker_state=Z

因此原代码虽然报告了超时,却没有完成承诺的进程组强制清理。对照修改仅用于确认根因,不表示已经提供了完整生产修复。

影响

残留构建进程可以继续占用 CPU、持有文件或写入安装/缓存目录;外层却可能已清理 stage、释放安装锁,或开始备用 registry 重试。这里确认的是进程残留,未声称已经观测到真实缓存损坏。

建议修复和验收

  • 强制终止定时器必须维持有效引用,或明确等待清理完成后才让包装进程返回。
  • 不要仅因直接子进程退出就推断整个进程组结束;正确处理已经退出的进程组,正常成功路径也不能遗留计时器。
  • 超时清理结束后才允许外层释放锁/删除 stage/进行后续尝试。
  • 回归测试覆盖:主进程退出但后代忽略 SIGTERM、主进程自身忽略 SIGTERM、正常成功、启动失败和取消;检查退出码及后代存活状态。
  • 本轮未在 macOS、Termux、Windows 实测,不把 Linux 结果表述为全平台通过。

已检查本仓库 Issues 和开放 PR;PR #1 尚未解决此处问题。上层项目:TokenNotIncluded/api.lmm.best 的 packages/lmm-scripts。

参考:Node.js timeout.unref 官方说明。

Activity

  1. added a commit that references this issue on Sep 20, 2026
    7a42eeb
  2. added a commit that references this issue on Sep 20, 2026
    fde672e
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions