Essential Go Executing commands  Edit on GitHub      File Issue

Timing out process execution

There’s no guarantee that a process will finish running so you might want to add a timeout.

cmd := exec.Command("go", "version")

err := cmd.Start()
if err != nil {
	log.Fatalf("cmd.Start() failed with '%s'\n", err)
}

var timedOut int32
timeout := 1 * time.Millisecond
stopTimer := time.AfterFunc(timeout, func() {
	cmd.Process.Kill()
	atomic.StoreInt32(&timedOut, 1)
})

err = cmd.Wait()
stopTimer.Stop()
didTimeout := atomic.LoadInt32(&timedOut) != 0
fmt.Printf("didTimeout: %v, err: %v\n", didTimeout, err)
didTimeout: true, err: signal: killed

Before calling cmd.Wait() we use time.AfterFunc() to kill the process after a timeout expired.

cmd.Process.Kill() makes cmd.Wait() exit with an error (signal: killed on Unix).

If cmd.Wait() finishes before a timeout, we cancel the timer.

Variable timedOut is int32 and not bool.

We use atomic.StoreInt32 and atomic.LoadInt32 because there is a subtle timing issues.

If a process finishes as usual, after cmd.Wait() exits and before we call stopTimer.Stop(), the timer might expire and execute the function anyway.

This is exceedingly unlikely but something to keep in mind.

Executing commands/
Timing out process execution
os.Exec gotchas
  ↑ ↓ to navigate     ↵ to select     Esc to close