Terminating a Process Started with os/exec in Golang
The other answers are right about calling Kill()
, but the parts regarding killing the process after a timeout are little outdated now.
This can be done now with the context
package and exec.CommandContext (example adapted from the example in the docs):
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
if err := exec.CommandContext(ctx, "sleep", "5").Run(); err != nil {
// This will fail after 100 milliseconds. The 5 second sleep
// will be interrupted.
}
}
From the docs:
The provided context is used to kill the process (by calling os.Process.Kill) if the context becomes done before the command completes on its own.
After the Run()
completes, you can inspect ctx.Err()
. If the timeout was reached, the type of the error returned will be DeadLineExceeded. If it's nil
, check the err
returned by Run()
to see if the command completed without errors.
Run and terminate an exec.Process
:
// Start a process:
cmd := exec.Command("sleep", "5")
if err := cmd.Start(); err != nil {
log.Fatal(err)
}
// Kill it:
if err := cmd.Process.Kill(); err != nil {
log.Fatal("failed to kill process: ", err)
}
Run and terminate an exec.Process
after a timeout:
ctx, cancel := context.WithTimeout(context.Background(), 3 * time.Second)
defer cancel()
if err := exec.CommandContext(ctx, "sleep", "5").Run(); err != nil {
// This will fail after 3 seconds. The 5 second sleep
// will be interrupted.
}
See this example in the Go docs
Legacy
Before Go 1.7, we didn't have the context
package and this answer was different.
Run and terminate an exec.Process
after a timeout using channels and a goroutine:
// Start a process:
cmd := exec.Command("sleep", "5")
if err := cmd.Start(); err != nil {
log.Fatal(err)
}
// Wait for the process to finish or kill it after a timeout (whichever happens first):
done := make(chan error, 1)
go func() {
done <- cmd.Wait()
}()
select {
case <-time.After(3 * time.Second):
if err := cmd.Process.Kill(); err != nil {
log.Fatal("failed to kill process: ", err)
}
log.Println("process killed as timeout reached")
case err := <-done:
if err != nil {
log.Fatalf("process finished with error = %v", err)
}
log.Print("process finished successfully")
}
Either the process ends and its error (if any) is received through done
or 3 seconds have passed and the program is killed before it's finished.