feat(cmd/transpilerd): update transpilerd to use http server package
The http package now contains a server that handles signals and proper shutdown procedure. It has now been updated to use it. The http package has also added a `ListenAndServe` convenience function that is similar to the `net/http` one, but also takes in a logger and will automatically use the most common signals when running an http server.pull/10616/head
parent
0c422a863f
commit
d8e4f4f2e0
|
@ -3,7 +3,6 @@ package main
|
|||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
nethttp "net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
|
@ -61,7 +60,9 @@ func transpileF(cmd *cobra.Command, args []string) {
|
|||
handler.Handler = transpileHandler
|
||||
|
||||
log.Printf("Starting transpilerd on %s\n", flags.bindAddr)
|
||||
log.Fatal(nethttp.ListenAndServe(flags.bindAddr, handler))
|
||||
if err := http.ListenAndServe(flags.bindAddr, handler, nil); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"os"
|
||||
"os/signal"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
@ -23,10 +24,10 @@ const DefaultShutdownTimeout = 20 * time.Second
|
|||
type Server struct {
|
||||
ShutdownTimeout time.Duration
|
||||
|
||||
srv *http.Server
|
||||
signalCh chan os.Signal
|
||||
logger *zap.Logger
|
||||
wg sync.WaitGroup
|
||||
srv *http.Server
|
||||
signals map[os.Signal]struct{}
|
||||
logger *zap.Logger
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
// NewServer returns a new server struct that can be used.
|
||||
|
@ -50,14 +51,17 @@ func (s *Server) Serve(listener net.Listener) error {
|
|||
// When we return, wait for all pending goroutines to finish.
|
||||
defer s.wg.Wait()
|
||||
|
||||
signalCh, cancel := s.notifyOnSignals()
|
||||
defer cancel()
|
||||
|
||||
errCh := s.serve(listener)
|
||||
select {
|
||||
case err := <-errCh:
|
||||
// The server has failed and reported an error.
|
||||
return err
|
||||
case <-s.signalCh:
|
||||
case <-signalCh:
|
||||
// We have received an interrupt. Signal the shutdown process.
|
||||
return s.shutdown()
|
||||
return s.shutdown(signalCh)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -74,7 +78,7 @@ func (s *Server) serve(listener net.Listener) <-chan error {
|
|||
return errCh
|
||||
}
|
||||
|
||||
func (s *Server) shutdown() error {
|
||||
func (s *Server) shutdown(signalCh <-chan os.Signal) error {
|
||||
// The shutdown needs to succeed in 20 seconds or less.
|
||||
ctx, cancel := context.WithTimeout(context.Background(), s.ShutdownTimeout)
|
||||
defer cancel()
|
||||
|
@ -87,7 +91,7 @@ func (s *Server) shutdown() error {
|
|||
go func() {
|
||||
defer s.wg.Done()
|
||||
select {
|
||||
case <-s.signalCh:
|
||||
case <-signalCh:
|
||||
cancel()
|
||||
case <-done:
|
||||
}
|
||||
|
@ -96,10 +100,45 @@ func (s *Server) shutdown() error {
|
|||
}
|
||||
|
||||
// ListenForSignals registers the the server to listen for the given signals
|
||||
// to shutdown the server.
|
||||
// to shutdown the server. The signals are not captured until Serve is called.
|
||||
func (s *Server) ListenForSignals(signals ...os.Signal) {
|
||||
if s.signalCh == nil {
|
||||
s.signalCh = make(chan os.Signal, 4)
|
||||
if s.signals == nil {
|
||||
s.signals = make(map[os.Signal]struct{})
|
||||
}
|
||||
|
||||
for _, sig := range signals {
|
||||
s.signals[sig] = struct{}{}
|
||||
}
|
||||
signal.Notify(s.signalCh, signals...)
|
||||
}
|
||||
|
||||
func (s *Server) notifyOnSignals() (_ <-chan os.Signal, cancel func()) {
|
||||
if len(s.signals) == 0 {
|
||||
return nil, func() {}
|
||||
}
|
||||
|
||||
// Retrieve which signals we want to be notified on.
|
||||
signals := make([]os.Signal, 0, len(s.signals))
|
||||
for sig := range s.signals {
|
||||
signals = append(signals, sig)
|
||||
}
|
||||
|
||||
// Create the signal channel and mark ourselves to be notified
|
||||
// of signals. Allow up to two signals for each signal type we catch.
|
||||
signalCh := make(chan os.Signal, len(signals)*2)
|
||||
signal.Notify(signalCh, signals...)
|
||||
return signalCh, func() { signal.Stop(signalCh) }
|
||||
}
|
||||
|
||||
// ListenAndServe is a convenience method for opening a listener using the address
|
||||
// and then serving the handler on that address. This method sets up the typical
|
||||
// signal handlers.
|
||||
func ListenAndServe(addr string, handler http.Handler, logger *zap.Logger) error {
|
||||
l, err := net.Listen("tcp", addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
server := NewServer(handler, logger)
|
||||
server.ListenForSignals(os.Interrupt, syscall.SIGTERM)
|
||||
return server.Serve(l)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue