When doing an HTTP server in Go the call to http.ListenAndServe(...)
will block until
the server stops. But it shouldn't stop. Ever.
That leaves us with a problem - we might want to stop the server!
There might be various reasons. Maybe we want to replace the binary with an updated version. Maybe we just want it to not run.
Fortunately instead of using the default .ListenAndServe(...)
we can create our own
http.Server
like this:
server := &http.Server{
Addr: ":8080",
Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
time.Sleep(5 * time.Second)
w.Write([]byte("Slept 5 seconds! Hello, World!"))
}),
}
This server, for the purpose of illustration, has only one simple handler that waits for five seconds and then returns the string.
After creating a server like this, we can shut it down gracefully:
err := server.Shutdown(context.Background())
Please notice that we pass a context.Context
to the .Shutdown(...)
function. That
gives us the flexibility to control the shutdown process in greater details if needed
(but for now we just use ).
Handling program shutdown
If we then setup a handler for signals (from the OS) to handle some events of
interrest, for example syscall.SIGINT
and syscall.SIGTERM
we start a goroutine that
will listen for any of these signals and that will then cal the .Shutdown(...)
function
on the server.
Like this:
// setup signal handler to gracefully shutdown the program
sig := make(chan os.Signal, 1)
signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-sig
fmt.Println("Shutting down server...")
err := server.Shutdown(context.Background())
if err != nil {
// handle the error
}
}()
The signals from the OS will be sent to allow the program to gracefully shut down.
Putting it all together
I have put everything here together with a lot of helper functions and signals to keep all the parts working.
There is a channel done
meant to signal that the program should exit. There is also a channel errCh
that is used for sending errors.
The full code is in the repository on Github.