Skip to content

Commit

Permalink
add request reject handler on shutdown #1
Browse files Browse the repository at this point in the history
  • Loading branch information
lnashier authored Mar 1, 2024
2 parents 5f38ea8 + 9f7af26 commit 25dbef8
Show file tree
Hide file tree
Showing 6 changed files with 44 additions and 16 deletions.
4 changes: 2 additions & 2 deletions examples/myhttpapp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
```
2 changes: 1 addition & 1 deletion examples/myhttpapp/configs/local.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"server": {
"port": 8080,
"shutdown": {
"gracetime": 1
"gracetime": 100
}
},
"log": {
Expand Down
2 changes: 1 addition & 1 deletion pkg/cli/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
21 changes: 21 additions & 0 deletions pkg/http/service/reject.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
25 changes: 16 additions & 9 deletions pkg/http/service/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -39,6 +40,7 @@ func NewServer(cfg *config.Config) *Server {
preempt: preempt,
router: mux.NewRouter(),
healthController: newHealthController(),
exitCh: make(chan struct{}),
}
}

Expand Down Expand Up @@ -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)
}
}
}
Expand Down Expand Up @@ -122,15 +126,18 @@ 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)
}
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)
}
6 changes: 3 additions & 3 deletions pkg/http/service/service.go
Original file line number Diff line number Diff line change
@@ -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
}

0 comments on commit 25dbef8

Please sign in to comment.