in runner/execer/os/process.go [36:104]
func (p *process) Wait() (result scootexecer.ProcessStatus) {
p.mutex.Lock()
p.waiting = true
p.mutex.Unlock()
// Wait for the output goroutines to finish then wait on the process itself to release resources.
p.wg.Wait()
pid := p.cmd.Process.Pid
err := p.cmd.Wait()
log.WithFields(
log.Fields{
"pid": pid,
"tag": p.Tag,
"jobID": p.JobID,
"taskID": p.TaskID,
}).Infof("Finished waiting for process")
p.mutex.Lock()
defer p.mutex.Unlock()
p.waiting = false
// Trace output with timeout since it seems CombinedOutput() sometimes fails to return.
if log.IsLevelEnabled(log.TraceLevel) {
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
ps, errDbg := exec.CommandContext(ctx, "ps", "-u", os.Getenv("USER"), "-opid,sess,ppid,pgid,rss,args").CombinedOutput()
log.WithFields(
log.Fields{
"pid": pid,
"tag": p.Tag,
"jobID": p.JobID,
"taskID": p.TaskID,
"ps": string(ps),
"err": errDbg,
"errCtx": ctx.Err(),
}).Tracef("Current ps for pid %d", pid)
cancel()
}
if p.result != nil {
return *p.result
} else {
p.result = &result
}
if err == nil {
// the command finished without an error
result.State = scootexecer.COMPLETE
result.ExitCode = 0
// stdout and stderr are collected and set by (invoke.go) runner
return result
}
if err, ok := err.(*exec.ExitError); ok {
// the command returned an error, if we can get a WaitStatus from the error,
// we can get the commands exit code
if status, ok := err.Sys().(syscall.WaitStatus); ok {
result.State = scootexecer.COMPLETE
result.ExitCode = scooterror.ExitCode(status.ExitStatus())
// stdout and stderr are collected and set by (invoke.go) runner
return result
}
result.State = scootexecer.FAILED
result.Error = "Could not find WaitStatus from exiterr.Sys()"
return result
}
result.State = scootexecer.FAILED
result.Error = err.Error()
return result
}