diff --git a/examples/myhttpapp/README.md b/examples/myhttpapp/README.md index d21b37f..8406b0f 100644 --- a/examples/myhttpapp/README.md +++ b/examples/myhttpapp/README.md @@ -3,12 +3,12 @@ # Build & Run ``` -go build -o bin/myhttpapp ./cmd/ +go build -o ./bin/myhttpapp ./cmd ./bin/myhttpapp ``` # Run ``` -go run cmd/main.go +go run ./cmd ``` \ No newline at end of file diff --git a/examples/myhttpapp/configs/local.json b/examples/myhttpapp/configs/local.json index 184c584..8c6fbbf 100755 --- a/examples/myhttpapp/configs/local.json +++ b/examples/myhttpapp/configs/local.json @@ -3,7 +3,7 @@ "server": { "port": 8080, "shutdown": { - "gracetime": 1 + "gracetime": 100 } }, "log": { diff --git a/pkg/cli/service.go b/pkg/cli/service.go index a09be8c..7d90945 100644 --- a/pkg/cli/service.go +++ b/pkg/cli/service.go @@ -66,7 +66,7 @@ func (s *Service) Start() error { func (s *Service) Stop() error { log.Info("Service#Stop enter") defer log.Info("Service#Stop exit") - s.exitCh <- struct{}{} + close(s.exitCh) return nil } diff --git a/pkg/http/service/reject.go b/pkg/http/service/reject.go new file mode 100644 index 0000000..6481b2d --- /dev/null +++ b/pkg/http/service/reject.go @@ -0,0 +1,21 @@ +package service + +import ( + "net/http" +) + +type reject struct { + h http.Handler + done chan struct{} +} + +func (rj *reject) ServeHTTP(w http.ResponseWriter, r *http.Request) { + select { + case <-rj.done: + // header: Retry-After + w.WriteHeader(http.StatusServiceUnavailable) + w.Write([]byte{}) + default: + rj.h.ServeHTTP(w, r) + } +} diff --git a/pkg/http/service/server.go b/pkg/http/service/server.go index f5e020c..cf8234f 100644 --- a/pkg/http/service/server.go +++ b/pkg/http/service/server.go @@ -20,7 +20,8 @@ type Server struct { router *mux.Router preempt *negroni.Negroni healthController *healthController - services []Service + components []Component + exitCh chan struct{} } func NewServer(cfg *config.Config) *Server { @@ -39,6 +40,7 @@ func NewServer(cfg *config.Config) *Server { preempt: preempt, router: mux.NewRouter(), healthController: newHealthController(), + exitCh: make(chan struct{}), } } @@ -71,14 +73,16 @@ func (s *Server) Stop() { log.Info("Server#Stop enter") defer log.Info("Server#Stop exit") + close(s.exitCh) + log.Info("Server#Stop server status set to down") s.healthController.setStatusDown() // Stop any long-running services within the app - if len(s.services) > 0 { - for _, sr := range s.services { - if err := sr.Stop(); err != nil { - log.Info("Server#Stop failed to stop a running service: %v", err) + if len(s.components) > 0 { + for _, comp := range s.components { + if err := comp.Stop(); err != nil { + log.Info("Server#Stop failed to stop a running component: %v", err) } } } @@ -122,7 +126,10 @@ func (s *Server) setupBuildInfoEndpoints() { // preHandlers can be optionally supplied, they will run before routeHandler in the order supplied func (s *Server) Register(path, method string, routeHandler http.Handler, preHandlers ...negroni.Handler) { chain := negroni.New(preHandlers...) - chain.UseHandler(routeHandler) + chain.UseHandler(&reject{ + h: routeHandler, + done: s.exitCh, + }) path = "/" + strings.TrimLeft(path, "/") if err := s.router.Handle(path, chain).Methods(method).GetError(); err != nil { log.Panic("Server#Register error %v building route for %v", err.Error(), path) @@ -130,7 +137,7 @@ func (s *Server) Register(path, method string, routeHandler http.Handler, preHan log.Info("Server#Register route [%v]%v registered", method, path) } -// Service registers service that will run within the app that requires stopping when server shuts down -func (s *Server) Service(sr Service) { - s.services = append(s.services, sr) +// Component registers a Component that will run within the app that requires stopping when server shuts down +func (s *Server) Component(comp Component) { + s.components = append(s.components, comp) } diff --git a/pkg/http/service/service.go b/pkg/http/service/service.go index fab2fa5..516ae3e 100644 --- a/pkg/http/service/service.go +++ b/pkg/http/service/service.go @@ -1,7 +1,7 @@ package service -// Service defines any service running within the app -type Service interface { - // Stop is to shut down the running service +// Component defines any component running within the app +type Component interface { + // Stop is to shut down the running component Stop() error }