Files
egutierrez 35aca86541 fix(infra): build tag !windows en process_kill/spawn/wait
Estas funciones usan syscall.Kill, Setpgid y ProcessKill (no disponibles
en Windows). Sin el build tag, el paquete functions/infra no cross-compila
para Windows desde apps que solo usan otras funciones del paquete.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 18:41:49 +02:00

45 lines
1.3 KiB
Go

//go:build !windows
package infra
import (
"fmt"
"syscall"
"time"
)
// ProcessKill sends SIGTERM to the process group of handle, then waits up to
// graceSec seconds for the process to exit. If it is still alive after the
// grace period, SIGKILL is sent. Returns an error only if the signal could not
// be delivered (e.g. the process group does not exist).
func ProcessKill(handle *ProcessHandle, graceSec int) error {
// Send SIGTERM to the process group (negative pid targets the group).
if err := syscall.Kill(-handle.Pid, syscall.SIGTERM); err != nil {
// ESRCH means the process is already gone — not an error from our view.
if err != syscall.ESRCH {
return fmt.Errorf("process_kill: sigterm: %w", err)
}
return nil
}
// Poll until the process exits or the grace period expires.
deadline := time.Now().Add(time.Duration(graceSec) * time.Second)
for time.Now().Before(deadline) {
// Check if process has exited by sending signal 0 (no-op).
err := syscall.Kill(-handle.Pid, 0)
if err == syscall.ESRCH {
// Process group is gone.
return nil
}
time.Sleep(100 * time.Millisecond)
}
// Still alive after grace period — escalate to SIGKILL.
if err := syscall.Kill(-handle.Pid, syscall.SIGKILL); err != nil {
if err != syscall.ESRCH {
return fmt.Errorf("process_kill: sigkill: %w", err)
}
}
return nil
}