The following works just fine when cmd finishes in the allotted time. However, the timeout is not working. While it does print \"It\'s dead Jim\", not only do
Go's defer statement schedules a function call (the deferred function) to be run immediately before the function executing the defer returns.
So the things after defer
defer time.AfterFunc(time.Second*2, func() {
fmt.Printf("Nobody got time fo that\n")
cmd.Process.Kill()
fmt.Printf("It's dead Jim\n")
}).Stop()
wouldn't be executed unless func() ends. Therefore, if "cmd.Wait()" never end, the "time.AfterFunc()" is never executed.
Removing "time.AfterFunc(...)" from defer can fix this problem, since "time.AfterFunc" could waits for the duration to elapse and then calls f in its own goroutine.
Here is a working version. I tested in my ubuntu box and it works. Save source as wait.go
package main
import "os/exec"
import "time"
import "bytes"
import "fmt"
func main() {
var output bytes.Buffer
cmd := exec.Command("sleep", "10s")
cmd.Stdout, cmd.Stderr = &output, &output
if err := cmd.Start(); err != nil {
fmt.Printf("command start error\n")
return
}
time.AfterFunc(time.Second*2, func() {
fmt.Printf("Nobody got time for that\n")
cmd.Process.Kill()
fmt.Printf("It's dead Jim\n")
})
cmd.Wait()
fmt.Printf("Done waiting\n")
}
Run the command:
time go run wait.go
Output:
Nobody got time for that
It's dead Jim
Done waiting
real 0m2.481s
user 0m0.252s
sys 0m0.452s
As @James Henstridge has commented that the above understanding is incorrect. Actually I had incomplete understanding of defer. The other half is "The arguments to the deferred function (which include the receiver if the function is a method) are evaluated when the defer executes". So the timer is truly created when defer is executed and thus timer will time out.
The problem is really why the process cannot be killed. I checked the go's pkg's code, it sends a SIGKILL in *nix like system to kill the process. The SIGKILL cannot be blocked and ignored. So it could be other possibilites such as the process itself is in TASK_UNINTERRUPTIBLE state.