Skip to content

Instantly share code, notes, and snippets.

@sanae10001
Created December 18, 2017 11:08
Show Gist options
  • Save sanae10001/9160036d42410618caa76c5e72cb937d to your computer and use it in GitHub Desktop.
Save sanae10001/9160036d42410618caa76c5e72cb937d to your computer and use it in GitHub Desktop.
A go graceful server
import (
"context"
"crypto/tls"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"golang.org/x/crypto/acme/autocert"
)
const (
DefaultWaitShutdown = 10 * time.Second
)
func ListenAndServe(addr string, h http.Handler) {
srv := Default()
srv.Addr = addr
srv.Handler = h
srv.Start()
}
func ListenAndServeTLS(addr string, h http.Handler, certFile, keyFile string) {
srv := Default()
srv.Addr = addr
srv.Handler = h
srv.StartTLS(certFile, keyFile)
}
func ListenAndServeAutoTLS(addr string, h http.Handler, m *autocert.Manager) {
srv := Default()
srv.Addr = addr
srv.Handler = h
srv.StartAutoTLS(m)
}
func New() *Server {
srv := new(Server)
srv.Logger = log.New(os.Stderr, "", log.LstdFlags)
return srv
}
func Default() *Server {
srv := new(Server)
srv.ReadTimeout = 10 * time.Second
srv.WriteTimeout = 10 * time.Second
srv.MaxHeaderBytes = 1 << 20 // 1M, 2**20
srv.Logger = log.New(os.Stderr, "", log.LstdFlags)
srv.WaitShutdown = DefaultWaitShutdown
return srv
}
// A graceful server
type Server struct {
http.Server
// Gracefully shutdown with a timeout. Default 10s
WaitShutdown time.Duration
// A logger
Logger *log.Logger
}
func (s *Server) logStart() {
s.Logger.Printf("Server listening on %s\n", s.Addr)
}
func (s *Server) Start() {
s.logStart()
go func() {
if err := s.ListenAndServe(); err != nil {
log.Fatalln(err)
}
}()
s.graceful()
}
func (s *Server) StartTLS(certFile, keyFile string) {
s.logStart()
go func() {
if err := s.ListenAndServeTLS(certFile, keyFile); err != nil {
log.Fatalln(err)
}
}()
s.graceful()
}
func (s *Server) StartAutoTLS(m *autocert.Manager) {
if m == nil {
m = &autocert.Manager{
Prompt: autocert.AcceptTOS,
}
}
s.TLSConfig = &tls.Config{
GetCertificate: m.GetCertificate,
}
s.StartTLS("", "")
}
func (s *Server) graceful() {
// Wait for interrupt, term, quit signal
quit := make(chan os.Signal)
signal.Notify(quit, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT)
<-quit
// Gracefully shutdown with a timeout of 10 seconds.
if s.WaitShutdown == 0 {
s.WaitShutdown = DefaultWaitShutdown
}
ctx, cancel := context.WithTimeout(context.Background(), s.WaitShutdown)
defer cancel()
s.Logger.Printf("Shutting down the server with timeout: %s\n", s.WaitShutdown)
if err := s.Shutdown(ctx); err != nil {
s.Logger.Fatalln(err)
} else {
s.Logger.Println("Server gracefully stopped!")
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment