86 lines
2.0 KiB
Go
86 lines
2.0 KiB
Go
|
package runner
|
||
|
|
||
|
import (
|
||
|
"fmt"
|
||
|
"os"
|
||
|
"os/exec"
|
||
|
"path/filepath"
|
||
|
"time"
|
||
|
|
||
|
"git.rootprojects.org/root/go-serviceman/service"
|
||
|
)
|
||
|
|
||
|
// Notes on spawning a child process
|
||
|
// https://groups.google.com/forum/#!topic/golang-nuts/shST-SDqIp4
|
||
|
|
||
|
func Run(conf *service.Service) {
|
||
|
originalBackoff := 1 * time.Second
|
||
|
maxBackoff := 1 * time.Minute
|
||
|
threshold := 5 * time.Second
|
||
|
|
||
|
backoff := originalBackoff
|
||
|
failures := 0
|
||
|
logfile := filepath.Join(conf.Logdir, conf.Name+".log")
|
||
|
|
||
|
binpath := conf.Exec
|
||
|
args := []string{}
|
||
|
if "" != conf.Interpreter {
|
||
|
binpath = conf.Interpreter
|
||
|
args = append(args, conf.Exec)
|
||
|
}
|
||
|
args = append(args, conf.Argv...)
|
||
|
|
||
|
for {
|
||
|
// setup the log
|
||
|
lf, err := os.OpenFile(logfile, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0644)
|
||
|
if nil != err {
|
||
|
fmt.Fprintf(os.Stderr, "Could not open log file %q\n", logfile)
|
||
|
lf = os.Stderr
|
||
|
} else {
|
||
|
defer lf.Close()
|
||
|
}
|
||
|
|
||
|
start := time.Now()
|
||
|
cmd := exec.Command(binpath, args...)
|
||
|
cmd.Stdin = nil
|
||
|
cmd.Stdout = lf
|
||
|
cmd.Stderr = lf
|
||
|
if "" != conf.Workdir {
|
||
|
cmd.Dir = conf.Workdir
|
||
|
}
|
||
|
err = cmd.Start()
|
||
|
if nil != err {
|
||
|
fmt.Fprintf(lf, "Could not start %q process: %s\n", conf.Name, err)
|
||
|
} else {
|
||
|
err = cmd.Wait()
|
||
|
if nil != err {
|
||
|
fmt.Fprintf(lf, "Process %q failed with error: %s\n", conf.Name, err)
|
||
|
} else {
|
||
|
fmt.Fprintf(lf, "Process %q exited cleanly\n", conf.Name)
|
||
|
fmt.Printf("Process %q exited cleanly\n", conf.Name)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// if this is a oneshot... so it is
|
||
|
if !conf.Restart {
|
||
|
fmt.Printf("Not restarting %q because `restart` set to `false`\n", conf.Name)
|
||
|
fmt.Fprintf(lf, "Not restarting %q because `restart` set to `false`\n", conf.Name)
|
||
|
break
|
||
|
}
|
||
|
|
||
|
end := time.Now()
|
||
|
if end.Sub(start) > threshold {
|
||
|
backoff = originalBackoff
|
||
|
failures = 0
|
||
|
} else {
|
||
|
failures += 1
|
||
|
fmt.Fprintf(lf, "Waiting %s to restart %q (%d consequtive immediate exits)\n", backoff, conf.Name, failures)
|
||
|
time.Sleep(backoff)
|
||
|
backoff *= 2
|
||
|
if backoff > maxBackoff {
|
||
|
backoff = maxBackoff
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|