gracefulshutdown

package module
v0.0.0-...-c4de050 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 24, 2023 License: MIT Imports: 6 Imported by: 0

README

Graceful shutdown decorator

Go Reference Pipeline Lint

A wrapper for your Go HTTP server so that it will finish responding to in-flight requests on interrupt signals before shutting down.

func main() {
  var (
    ctx        = context.Background()
    httpServer = &http.Server{Addr: ":8080", Handler: http.HandlerFunc(acceptancetests.SlowHandler)}
    server     = gracefulshutdown.NewServer(httpServer)
  )

  if err := server.ListenAndServe(ctx); err != nil {
    // this will typically happen if our responses aren't written before the ctx deadline, not much can be done
    log.Fatalf("uh oh, didnt shutdown gracefully, some responses may have been lost %v", err)
  }

  // hopefully, you'll always see this instead
  log.Println("shutdown gracefully! all responses were sent")
}

The problem

  • You're running a HTTP server, and deploying it many times per day
  • Sometimes, you might be deploying a new version of the code while it is trying to handle a request, and if you're not handling this gracefully you'll either:
    • Not get a response
    • Or the reverse-proxy in front of your service will complain about your service and return a 502

The solution

Graceful shutdown!

  • Listen to interrupt signals
  • Rather than killing the program straight away, instead call http.Server.Shutdown which will let requests, connections e.t.c drain before killing the server
  • This should mean in most cases, the server will finish the currently running requests before stopping

There are a few examples of this out there, I thought I'd roll my own, so I could understand it better, and structure it in a non-confusing way, hopefully.

Almost everything boils down to a decorator pattern in the end. You provide my library a *http.Server and it'll return you back a *gracefulshutdown.Server. Just call ListenAndServe, and it'll gracefully shutdown on an os signal.

Example usage and testing

See acceptancetests/withgracefulshutdown/main.go for an example

There are two binaries in this project with accompanying acceptance tests to verify the functionality that live inside /acceptancetests.

Both tests build the binaries, run them, fire a HTTP GET and then send an interrupt signal to tell the server to stop.

The two binaries allow us to test both scenarios

  1. A "slow" HTTP server with no graceful shutdown. For this we assert that we do get an error, because the server should shutdown immediately and any in-flight requests will fail.
  2. Another slow HTTP server with graceful shutdown. Same test again, but this time we assert we don't get an error as we expect to get a response before the server is terminated.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type HTTPServer

type HTTPServer interface {
	ListenAndServe() error
	Shutdown(ctx context.Context) error
}

HTTPServer is an abstraction of something that listens for connections and do HTTP things. 99% of the time, you'll pass in a net/http/Server.

type Server

type Server struct {
	Delegate HTTPServer
	// contains filtered or unexported fields
}

Server wraps around a HTTPServer and will gracefully shutdown when it receives a shutdown signal.

func NewServer

func NewServer(server HTTPServer, options ...ServerOption) *Server

NewServer returns a Server that can gracefully shutdown on shutdown signals.

func (*Server) ListenAndServe

func (s *Server) ListenAndServe(ctx context.Context) error

ListenAndServe will call the ListenAndServe function of the delegate HTTPServer you passed in at construction. On a signal being sent to the shutdown signal provided in the constructor, it will call the server's Shutdown method to attempt to gracefully shutdown.

type ServerOption

type ServerOption func(server *Server)

ServerOption provides ways of configuring Server.

func WithShutdownSignal

func WithShutdownSignal(shutdownSignal <-chan os.Signal) ServerOption

WithShutdownSignal WithShutdownSignals allows you to listen to whatever signals you like, rather than the default ones defined in signal.go.

func WithTimeout

func WithTimeout(timeout time.Duration) ServerOption

WithTimeout lets you set your own timeout for waiting for graceful shutdown. By default this is set to 30 seconds (k8s' default TerminationGracePeriod).

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL