diff --git a/a_test.go b/a_test.go index ea5f838..68bce92 100644 --- a/a_test.go +++ b/a_test.go @@ -49,6 +49,11 @@ func (self *catchSignals) Kill() (err error) { if err != nil { return } + // to avoid zombie + _, err = self.Process.Wait() + if err != nil { + return + } return } diff --git a/daemon.go b/daemon.go index 9ad161a..43e0f65 100644 --- a/daemon.go +++ b/daemon.go @@ -69,11 +69,13 @@ func (self *Daemon) Run() { uid, err := strconv.Atoi(self.user.Uid) if err != nil { self.Control.state <- err + return } gid, err := strconv.Atoi(self.user.Gid) if err != nil { self.Control.state <- err + return } // https://golang.org/pkg/syscall/#SysProcAttr @@ -156,11 +158,10 @@ func New(cfg *Config) (*Daemon, error) { supDir = filepath.Join(d, "supervise") } - // buffer because goroutine might write before main goroutine starts control := &Control{ - fifo: make(chan Return, 1), + fifo: make(chan Return), quit: make(chan struct{}), - state: make(chan error, 1), + state: make(chan error), } // if ctrl create supervise dir diff --git a/daemonrun_test.go b/daemonrun_test.go index f354733..56b668f 100644 --- a/daemonrun_test.go +++ b/daemonrun_test.go @@ -48,9 +48,9 @@ func TestDaemonRun(t *testing.T) { d := &Daemon{ Config: cfg, Control: &Control{ - fifo: make(chan Return, 1), + fifo: make(chan Return), quit: make(chan struct{}), - state: make(chan error, 1), + state: make(chan error), }, Forker: &myFork{}, Logger: &LogWriter{ diff --git a/signals_test.go b/signals_test.go index 2c8925d..7398ca5 100644 --- a/signals_test.go +++ b/signals_test.go @@ -1,8 +1,8 @@ package immortal import ( - "io/ioutil" - "log" + // "io/ioutil" + // "log" "os" "os/signal" "path/filepath" @@ -17,12 +17,16 @@ func TestHelperProcessSignals(*testing.T) { } c := make(chan os.Signal, 1) signal.Notify(c, os.Interrupt, os.Kill) - <-c - os.Exit(0) + select { + case <-c: + os.Exit(0) + case <-time.After(30 * time.Second): + os.Exit(1) + } } func TestSignals(t *testing.T) { - log.SetOutput(ioutil.Discard) + // log.SetOutput(ioutil.Discard) base := filepath.Base(os.Args[0]) // "exec.test" dir := filepath.Dir(os.Args[0]) // "/tmp/go-buildNNNN/os/exec/_test" if dir == "." { @@ -42,14 +46,14 @@ func TestSignals(t *testing.T) { Child: filepath.Join(parentDir, "child.pid"), }, } - c := make(chan os.Signal, 1) + c := make(chan os.Signal) wait := make(chan struct{}) d := &Daemon{ Config: cfg, Control: &Control{ - fifo: make(chan Return, 1), + fifo: make(chan Return), quit: make(chan struct{}), - state: make(chan error, 1), + state: make(chan error), }, Forker: &myFork{}, Logger: &LogWriter{ @@ -172,12 +176,55 @@ func TestSignals(t *testing.T) { for old_pid == d.process.GetPid() { time.Sleep(time.Second) } - // create zombie - println(d.process.GetPid()) - d.Control.fifo <- Return{err: nil, msg: "d"} - for { + // test down + d.Control.fifo <- Return{err: nil, msg: "down"} + for sup.IsRunning(d.process.GetPid()) { + // waiting for process to exit + } + + // test up + // bring up the service (new pid expected) + d.Control.fifo <- Return{err: nil, msg: "up"} + for !sup.IsRunning(d.process.GetPid()) { + } + d.Control.fifo <- Return{err: nil, msg: "once"} + for d.count_defer != 1 { + } + expect(t, d.count, uint32(1), "in 194") + expect(t, d.count_defer, uint32(1), "in 195") + + // save old pid + old_pid = d.process.GetPid() + // send kill (should not start) + d.Control.fifo <- Return{err: nil, msg: "k"} + for sup.IsRunning(d.process.GetPid()) { + } + expect(t, old_pid, d.process.GetPid(), "in 203") + expect(t, false, sup.IsRunning(d.process.GetPid()), "in 204") + + // test up + // bring up the service (new pid expected) + d.Control.fifo <- Return{err: nil, msg: "up"} + for !sup.IsRunning(d.process.GetPid()) { + } + old_pid = d.process.GetPid() + + // send kill (should re-start, and get new pid) + d.Control.fifo <- Return{err: nil, msg: "k"} + for sup.IsRunning(d.process.GetPid()) { + } + select { + case <-wait: + case <-time.After(1 * time.Second): + t.Fatal("timeout waiting for pid") } + for old_pid == d.process.GetPid() { + } + expect(t, true, sup.IsRunning(d.process.GetPid())) + + // quit + d.Control.fifo <- Return{err: nil, msg: "exit"} } func waitSig(t *testing.T, c <-chan os.Signal, sig os.Signal) { diff --git a/supervisor.go b/supervisor.go index 4e37f9b..df813da 100644 --- a/supervisor.go +++ b/supervisor.go @@ -6,6 +6,7 @@ import ( "io/ioutil" "log" "os" + "os/exec" "strconv" "strings" "syscall" @@ -84,10 +85,12 @@ func Supervise(s Supervisor, d *Daemon) { return case state := <-d.Control.state: if state != nil { - if state.Error() == "EXIT" { + if exitError, ok := state.(*exec.ExitError); ok { + log.Print(exitError) + } else if state.Error() == "EXIT" { log.Printf("PID: %d Exited", d.process.GetPid()) } else { - log.Print(state.Error()) + log.Print(state) } }