fix(process): kill process groups on shutdown

This commit is contained in:
Virgil 2026-04-04 02:10:35 +00:00
parent 38a9f034a7
commit 26af69d87b
2 changed files with 20 additions and 5 deletions

View file

@ -166,6 +166,22 @@ func (p *Process) kill() (bool, error) {
return true, p.cmd.Process.Kill()
}
// killTree forcefully terminates the process group when one exists.
func (p *Process) killTree() (bool, error) {
p.mu.Lock()
defer p.mu.Unlock()
if p.Status != StatusRunning {
return false, nil
}
if p.cmd == nil || p.cmd.Process == nil {
return false, nil
}
return true, syscall.Kill(-p.cmd.Process.Pid, syscall.SIGKILL)
}
// Shutdown gracefully stops the process: SIGTERM, then SIGKILL after grace period.
// If GracePeriod was not set (zero), falls back to immediate Kill().
// If KillGroup is set, signals are sent to the entire process group.

View file

@ -112,7 +112,7 @@ func (s *Service) OnShutdown(ctx context.Context) error {
s.mu.RUnlock()
for _, p := range procs {
_ = p.Kill()
_, _ = p.killTree()
}
return nil
@ -165,10 +165,9 @@ func (s *Service) StartWithOptions(ctx context.Context, opts RunOptions) (*Proce
cmd.Env = append(cmd.Environ(), opts.Env...)
}
// Detached processes get their own process group
if opts.Detach {
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
}
// Put every subprocess in its own process group so shutdown can terminate
// the full tree without affecting the parent process.
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
// Set up pipes
stdout, err := cmd.StdoutPipe()