I have an executable that I need to run. Also, I want the parent process to send signal to the child process. I have a soft timeout and a hardtimeout value.
The sequence should be: • If child is still running after soft time, send SIGHUP, and log • If child is still running after hard timeout, send SIGTERM, and log • If child is still running, after 5 seconds, send SIGKILL, and log
Fairly new to go, this is the code I tried.
Do I need to call cmd.Wait() at the end of the program? Also, how do I check if the child process died because of the signal that I had sent. I did find Get exit code - Go but not quite convinced how to use it.
Also, does the code look correct?
I understand that the cmd.Wait() will return only once the child processes the signal it has received. But in the "testExecutable" code, how should it return to the parent(that it is dying now)
Here is my code:
func run() error{
cmd := exec.Command("testExecutable", "helpMe", "-s", "testMe")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
startTime := time.Now()
if err := cmd.Start(); err != nil {
return fmt.Errorf("Failed to start the executable")
}
rChan := make(chan error, 1)
go func() {
var err error
defer func() {
if err != nil {
fmt.Errorf(err.Error())
}
rChan <- err
}()
for time.Now().Sub(startTime) < time.Duration(HardTimeout) {
time.Sleep(time.Second)
if time.Now().Sub(startTime) < time.Duration(SoftTimeout) && cmd.ProcessState.Exited() {
fmt.Println("process ended before soft timeout")
return
} else if time.Now().Sub(startTime) > time.Duration(SoftTimeout) && time.Now().Sub(startTime) < time.Duration(HardTimeout) && !cmd.ProcessState.Exited() {
if err := syscall.Kill(-cmd.Process.Pid, syscall.SIGHUP); err != nil {
return
}
if cmd.ProcessState.Exited() {
fmt.Println(" process was killed after soft timeout")
return
}
} else if time.Now().Sub(startTime) < time.Duration(SoftTimeout) {
continue
}
if time.Now().Sub(startTime) > time.Duration(HardTimeout) && !cmd.ProcessState.Exited() {
if err := syscall.Kill(-cmd.Process.Pid, syscall.SIGINT); err != nil {
return
}
time.Sleep(time.Second * 5)
if !cmd.ProcessState.Exited() {
if err := syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL); err != nil {
return
}
}else {
fmt.Println(" process was killed after hard timeout")
return
}
}
}
}()
var ierr error ierr,_ = <- rChan err = cmd.Wait() if err != nil { if ierr != nil { return fmt.Errorf(process %d Terminated", cmd.Process.Pid) } } return nil }