Web Package

This code is almost a direct copy of the example code at server.Shutdown. I used a context to signal the shutdown, and I added a timeout so the shutdown couldn’t hang forever.

While the global ListenAndServe() function is more convenient than creating a server object, if you are worried about shutting it down you will likely be worried about the TLS configuration as well.

A note about the implementation: I’ve see a few comments online that the idleConnsClosed channel is not needed because the Shutdown() call doesn’t return until everything is cleaned up. That is good in sequential code but this call to Shutdown is in a goroutine. The call to ListenAndServe will exit almost immediately after Shutdown is called, well before it is complete.

 1package web
 2
 3import (
 4	"context"
 5	"log"
 6	"net/http"
 7	"sync"
 8	"time"
 9)
10
11func Run(ctx context.Context, addr string, wg *sync.WaitGroup) {
12	defer wg.Done()
13
14	srv := &http.Server{Addr: addr}
15	idleConnsClosed := make(chan struct{})
16
17	// This goroutine will Wait for ctx to be triggered
18	go func() {
19		<-ctx.Done()
20		timeout, cancel := context.WithTimeout(context.Background(), 30*time.Second)
21		defer cancel()
22		if err := srv.Shutdown(timeout); err != nil {
23			log.Printf("HTTP server Shutdown: %v", err)
24		}
25		close(idleConnsClosed)
26	}()
27
28	if err := srv.ListenAndServe(); err != http.ErrServerClosed {
29		log.Printf("HTTP server ListenAndServe: %v", err)
30	}
31	<-idleConnsClosed
32	log.Print("HTTP Server closed")
33}