9be9a87fa0
Add Windows specific shutdown code paths so stopping of child processes is more reliable: - stopping llama-swap won't leave behind any child processes it created - uses Job Objects in Windows so the whole llama-swap tree is closed by the os - add procCtx to baseRouter. It replaces shutdownCtx as a signal for managing lifetime state. - shutdownCtx is only used by the router to stop handling new requests during shutdown - improve debug logging to make it easier to trace source of issues Fixes #804 Updates #807
54 lines
1.8 KiB
Go
54 lines
1.8 KiB
Go
//go:build windows
|
|
|
|
package process
|
|
|
|
import (
|
|
"fmt"
|
|
"os/exec"
|
|
"syscall"
|
|
)
|
|
|
|
// setProcAttributes sets platform-specific process attributes. CREATE_NO_WINDOW
|
|
// keeps the upstream from spawning its own console window.
|
|
func setProcAttributes(cmd *exec.Cmd) {
|
|
cmd.SysProcAttr = &syscall.SysProcAttr{
|
|
HideWindow: true,
|
|
CreationFlags: 0x08000000, // CREATE_NO_WINDOW
|
|
}
|
|
}
|
|
|
|
// terminateProcessTree requests a graceful shutdown of the whole process tree
|
|
// rooted at cmd.Process. Windows has no SIGTERM or process-group signalling, so
|
|
// we shell out to `taskkill /t`, which walks the child tree by PID — the
|
|
// equivalent of signalling a Unix process group. Without /f, taskkill asks the
|
|
// processes to close rather than force-killing them.
|
|
func terminateProcessTree(cmd *exec.Cmd) error {
|
|
return taskkillProcessTree(cmd, false)
|
|
}
|
|
|
|
// killProcessTree force-terminates the whole process tree rooted at cmd.Process
|
|
// via `taskkill /f /t`, so any descendant that ignored or outlived the graceful
|
|
// request is killed alongside the parent rather than leaked as an orphan.
|
|
func killProcessTree(cmd *exec.Cmd) error {
|
|
return taskkillProcessTree(cmd, true)
|
|
}
|
|
|
|
// taskkillProcessTree runs taskkill against cmd.Process.Pid. The /t flag
|
|
// terminates the process together with any child processes it started, which is
|
|
// the Windows analogue of signalling a Unix process group via its negative PID.
|
|
// When force is true the /f flag force-kills; otherwise taskkill requests a
|
|
// graceful close.
|
|
func taskkillProcessTree(cmd *exec.Cmd, force bool) error {
|
|
if cmd == nil || cmd.Process == nil {
|
|
return nil
|
|
}
|
|
args := make([]string, 0, 4)
|
|
if force {
|
|
args = append(args, "/f")
|
|
}
|
|
args = append(args, "/t", "/pid", fmt.Sprintf("%d", cmd.Process.Pid))
|
|
kill := exec.Command("taskkill", args...)
|
|
setProcAttributes(kill)
|
|
return kill.Run()
|
|
}
|