6ea551362e
Note: The original proxy/process_unix.go had a noop for setProcAttributes so it also did not stop grandchildren processes. This patch adds that capability and improves reliability. -- Stop() no longer hangs on a shell wrapper that forks the real binary. The upstream is built with exec.CommandContext + cmd.Cancel + cmd.WaitDelay, so cmd.Wait() returns even when a forked grandchild inherits the stdout/stderr pipes. killProcess sends the stop signal directly (not by cancelling the context) so cmd.WaitDelay measures from process exit and never silently caps the caller's graceful timeout. The upstream is also started in its own process group (Setpgid) on Unix, so the graceful SIGTERM — and the SIGKILL escalation after the timeout — are delivered to the whole group via the negative PID. A forked grandchild is reaped with its parent instead of leaking as an orphan. The loading-spinner SSE goroutine can no longer panic when it outlives the request. net/http recycles the response writer via Reset(nil) once ServeHTTP returns; the orphaned goroutine then flushed against a nil-backed writer and crashed with a SIGSEGV. A release() fence on loadingWriter lets any in-flight write finish then short-circuits later writes/flushes, and all three ServeHTTP select branches run a finishLoading helper (cancelLoad, waitForCompletion, release) before the writer is reclaimed. - internal/process: exec.CommandContext + WaitDelay, Setpgid process groups, group-wide SIGTERM/SIGKILL teardown - internal/router: release() fence + finishLoading on loadingWriter fixes #804
37 lines
1005 B
Go
37 lines
1005 B
Go
//go:build windows
|
|
|
|
package process
|
|
|
|
import (
|
|
"os/exec"
|
|
"syscall"
|
|
)
|
|
|
|
// setProcAttributes sets platform-specific process attributes
|
|
func setProcAttributes(cmd *exec.Cmd) {
|
|
cmd.SysProcAttr = &syscall.SysProcAttr{
|
|
HideWindow: true,
|
|
CreationFlags: 0x08000000, // CREATE_NO_WINDOW
|
|
}
|
|
}
|
|
|
|
// terminateProcessTree asks the upstream process to stop. Windows has no
|
|
// process-group signalling here — process-tree teardown is handled by the
|
|
// configured CmdStop, which defaults to `taskkill /f /t` — so this preserves
|
|
// the previous single-process SIGTERM behaviour.
|
|
func terminateProcessTree(cmd *exec.Cmd) error {
|
|
if cmd == nil || cmd.Process == nil {
|
|
return nil
|
|
}
|
|
return cmd.Process.Signal(syscall.SIGTERM)
|
|
}
|
|
|
|
// killProcessTree force-terminates the upstream process. Tree teardown on
|
|
// Windows relies on CmdStop (taskkill /t); this kills the launched process.
|
|
func killProcessTree(cmd *exec.Cmd) error {
|
|
if cmd == nil || cmd.Process == nil {
|
|
return nil
|
|
}
|
|
return cmd.Process.Kill()
|
|
}
|