Add support to restart on program exit

This commit is contained in:
Max Claus Nunes 2018-06-19 00:50:05 -03:00
parent 99cc752b38
commit 68c9d713ae
3 changed files with 51 additions and 5 deletions

33
main.go
View File

@ -3,6 +3,7 @@ package main
import (
"fmt"
"os"
"os/exec"
"os/signal"
"path/filepath"
"syscall"
@ -167,24 +168,40 @@ func runGaper(cfg *Config) error {
return fmt.Errorf("watcher error: %v", err)
}
var changeRestart bool
go watcher.Watch()
for {
select {
case event := <-watcher.Events:
logger.Debug("Detected new changed file: ", event)
changeRestart = true
restart(builder, runner)
case err := <-watcher.Errors:
return fmt.Errorf("error on watching files: %v", err)
case err := <-runner.Errors():
if changeRestart {
changeRestart = false
} else {
logger.Debug("Detected program exit: ", err)
if err = handleProgramExit(builder, runner, err); err != nil {
return err
}
}
default:
logger.Debug("Waiting watch event")
time.Sleep(time.Duration(cfg.PollInterval) * time.Millisecond)
}
}
}
func restart(builder Builder, runner Runner) error {
if err := runner.Kill(); err != nil {
return fmt.Errorf("kill error: %v", err)
logger.Debug("Restarting program")
// kill process if it is running
if !runner.Exited() {
if err := runner.Kill(); err != nil {
return fmt.Errorf("kill error: %v", err)
}
}
if err := builder.Build(); err != nil {
@ -198,6 +215,16 @@ func restart(builder Builder, runner Runner) error {
return nil
}
func handleProgramExit(builder Builder, runner Runner, err error) error {
_, ok := err.(*exec.ExitError)
if !ok {
return fmt.Errorf("couldn't handle program crash restart: %v", err)
}
restart(builder, runner)
return nil
}
func shutdown(runner Runner) {
c := make(chan os.Signal, 2)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)

View File

@ -16,6 +16,8 @@ const OSWindows = "windows"
type Runner interface {
Run() (*exec.Cmd, error)
Kill() error
Errors() chan error
Exited() bool
}
type runner struct {
@ -24,6 +26,7 @@ type runner struct {
writer io.Writer
command *exec.Cmd
starttime time.Time
errors chan error
}
// NewRunner ...
@ -33,6 +36,7 @@ func NewRunner(writer io.Writer, bin string, args []string) Runner {
args: args,
writer: writer,
starttime: time.Now(),
errors: make(chan error),
}
}
@ -91,6 +95,11 @@ func (r *runner) Exited() bool {
return r.command != nil && r.command.ProcessState != nil && r.command.ProcessState.Exited()
}
// Errors ...
func (r *runner) Errors() chan error {
return r.errors
}
func (r *runner) runBin() error {
r.command = exec.Command(r.bin, r.args...) // nolint gas
stdout, err := r.command.StdoutPipe()
@ -113,7 +122,13 @@ func (r *runner) runBin() error {
// TODO: handle or log errors
go io.Copy(r.writer, stdout) // nolint errcheck
go io.Copy(r.writer, stderr) // nolint errcheck
go r.command.Wait() // nolint errcheck
// wait for exit errors
go func() {
if err := r.command.Wait(); err != nil {
r.errors <- err
}
}()
return nil
}

View File

@ -8,10 +8,14 @@ import (
)
func main() {
http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
http.HandleFunc("/foo", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path)) // nolint gas
})
http.HandleFunc("/bar", func(w http.ResponseWriter, r *http.Request) {
log.Fatal("Forced failure")
})
log.Println("Starting server")
log.Fatal(http.ListenAndServe(":8080", nil))
}