mirror of https://github.com/maxcnunes/gaper.git
Add support to restart on program exit
This commit is contained in:
parent
99cc752b38
commit
68c9d713ae
33
main.go
33
main.go
|
@ -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)
|
||||
|
|
17
runner.go
17
runner.go
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue