diff --git a/gosuv.go b/gosuv.go index f9f51bc..5ef784a 100644 --- a/gosuv.go +++ b/gosuv.go @@ -194,7 +194,15 @@ func grpcDial(network, addr string) (*grpc.ClientConn, error) { })) } -func ShutdownAction(ctx *cli.Context, client pb.GoSuvClient) { +func ShutdownAction(ctx *cli.Context) { + conn, err := connect(ctx) + if err != nil { + fmt.Println("server already closed") + return + } + defer conn.Close() + + client := pb.NewGoSuvClient(conn) res, err := client.Shutdown(context.Background(), &pb.NopRequest{}) if err != nil { log.Fatal(err) @@ -273,7 +281,7 @@ func initCli() { { Name: "shutdown", Usage: "Shutdown server", - Action: wrap(ShutdownAction), + Action: ShutdownAction, }, { Name: "serv", diff --git a/program.go b/program.go index 5fa4ff1..c32a636 100644 --- a/program.go +++ b/program.go @@ -78,8 +78,8 @@ type Program struct { Sig chan os.Signal `json:"-"` Info *ProgramInfo `json:"info"` - retry int - stopped bool + retry int + stopc chan bool } func NewProgram(info *ProgramInfo) *Program { @@ -92,6 +92,7 @@ func NewProgram(info *ProgramInfo) *Program { Status: ST_STANDBY, Sig: make(chan os.Signal), Info: info, + stopc: make(chan bool), } } @@ -121,51 +122,57 @@ func (p *Program) createLog() (*os.File, error) { } func (p *Program) sleep(d time.Duration) { - // FIXME(ssx): when signal comes, finished sleep - time.Sleep(d) + select { + case <-p.stopc: + return + case <-time.After(time.Second * 2): + } } func (p *Program) RunWithRetry() { - p.stopped = false for p.retry = 0; p.retry < p.Info.StartRetries; p.retry += 1 { - p.Run() - if p.stopped { - p.setStatus(ST_STOPPED) + // wait program to exit + select { + case err := <-GoFunc(p.Run): + log.Info(p.Info.Name, err) + case <-p.stopc: return } + // retry if p.retry+1 < p.Info.StartRetries { p.setStatus(ST_RETRYWAIT) - p.sleep(time.Second * 2) // RETRYWAIT + select { + case <-p.stopc: + return + case <-time.After(time.Second * 2): + } } } p.setStatus(ST_FATAL) } func (p *Program) Run() (err error) { - if err := p.Start(); err != nil { - log.Println("start:", err) - p.setStatus(ST_FATAL) - return err + if err = p.Start(); err != nil { + return } p.setStatus(ST_RUNNING) defer func() { if out, ok := p.Cmd.Stdout.(io.Closer); ok { out.Close() } - if !p.stopped && err != nil { - log.Warnf("program finish: %v", err) - p.setStatus(ST_FATAL) - } else { - p.setStatus(ST_STOPPED) - } + log.Warnf("program finish: %v", err) }() err = p.Wait() return } func (p *Program) Stop() error { - p.stopped = true + select { + case p.stopc <- true: // stopc may not recevied + case <-time.After(time.Millisecond * 50): + } p.Terminate(syscall.SIGKILL) + p.setStatus(ST_STOPPED) return nil } diff --git a/service.go b/service.go index 60c1840..0a220bf 100644 --- a/service.go +++ b/service.go @@ -70,7 +70,7 @@ func (s *PbSuvServer) Status(ctx context.Context, in *pb.NopRequest) (res *pb.St ps := &pb.ProgramStatus{} ps.Name = proto.String(program.Info.Name) ps.Status = proto.String(program.Status) - ps.Extra = proto.String("nothing") + ps.Extra = proto.String("...") res.Programs = append(res.Programs, ps) } return