Hi Michele, Great to hear that!
I think we also need to painstakingly measure the action crash timeout to avoid the delay for cold starts. Waiting for 100ms seems to be unduly. Starting a new go routine is in the magnitude of microseconds, I’d expect go runtime to fail the processes fast as well... regards, Vadim. On Sun, 11 Mar 2018 at 13:19 Michele Sciabarra <[email protected]> wrote: > Hi Vadim, your suggestion worked. > > I was able to simplify the code a bit, but thanks to this I can remove the > handshake while detecting immediately crashing executable. Fo the records, > here is the code and the test: > > // startAndCheck > func startAndCheck(cmd *exec.Cmd) error { > //fmt.Println(cmd.Path) > err := cmd.Start() > if err != nil { > return err > } > ch := make(chan error) > go func() { ch <- cmd.Wait() }() > select { > case <-ch: > return fmt.Errorf("command exited") > case <-time.After(100 * time.Millisecond): > return nil > } > } > > func Example_startAndCheck() { > // err > cmd := exec.Command("/does/not/exists") > cmd.StdinPipe() > cmd.StdoutPipe() > fmt.Println(startAndCheck(cmd)) > // immediate exit > cmd = exec.Command("/bin/true") > cmd.StdinPipe() > cmd.StdoutPipe() > fmt.Println(startAndCheck(cmd)) > // immediate exit with output > cmd = exec.Command("/bin/pwd") > cmd.StdinPipe() > cmd.StdoutPipe() > fmt.Println(startAndCheck(cmd)) > // unwanted banner > cmd = exec.Command("/usr/bin/bc") > cmd.StdinPipe() > cmd.StderrPipe() > fmt.Println(startAndCheck(cmd)) > // pipe loop > cmd = exec.Command("/bin/cat") > cmd.StdinPipe() > cmd.StderrPipe() > fmt.Println(startAndCheck(cmd)) > // Output: > // fork/exec /does/not/exists: no such file or directory > // command exited > // command exited > // <nil> > // <nil> > } > > > > -- > Michele Sciabarra > [email protected] > > On Sat, Mar 10, 2018, at 9:47 PM, Vadim Raskin wrote: > > >> So, how can I check the process is actually terminated ? > > > > Hi Michele, > > > > what about using cmd.Wait() to check whether the process exited after you > > started a go action? It will return a non-nil in case of error, otherwise > > blocks forever waiting the process to finish. Waiting for a reasonable > > amount of time to make sure that process doesn't exit and close the /init > > call afterwards, would it cover the case you mentioned? > > > > Just to make sure we talk about the same thing: > > > > errorChan := chan string > > > > cmd := exec.Command("userBinary") > > cmd.Start() > > // wait for failure to happen > > go func(){ > > err := cmd.Wait() > > if(err != nil){ > > errorChan <- "exited with failure" > > } > > else { > > close(errorChan) > > } > > }() > > // wait at most 10ms for an error to happen > > go func(){ > > time.Sleep(10 * time.Millisecond) > > errorChan <- "happy" > > } > > runResult <- errorChan > > // further processing. > > > > I haven't tested this code, it also needs to do some clean up of the Wait > > go routine, but hopefully the logic is clear. > > > > regards, > > Vadim. > > > > On Fri, Mar 9, 2018 at 3:18 PM Michele Sciabarra <[email protected]> > > wrote: > > > > > > I would prefer it not be there, but can see the convenience of > detecting > > > > that an app has immediately crashed. If we can find another way to do > > > > that via process inspection, that would be better in my view. > > > > > > > The problem can be summarised into this code: > > > > > > // this command exits > > > cmd := exec.Command("true") > > > out, err := cmd.StdoutPipe() > > > > > > err = cmd.Start() > > > fmt.Println(err) > > > // this is nil! no error! > > > > > > // even worse! attempted to detect > > > err = cmd.Process.Signal(syscall.Signal(0)) > > > // this is nil too! no error! > > > fmt.Println(err) > > > > > > So, how can I check the process is actually terminated ? > > > >
