I am using the Mux library from Gorilla Web Toolkit along with the bundled Go http server.
The problem is that in my application the HTTP server is only one component and it is required to stop and start at my discretion.
When I call http.ListenAndServe(fmt.Sprintf(":%d", service.Port()), service.router)
it blocks and I cannot seem to stop the server from running.
I am aware this has been a problem in the past, is that still the case? Are there any new solutions?
WaitGroup in main(), call Add(1) on it and pass a pointer to it to startHttpServer() and call defer waitGroup. Done() at start of the goroutine that has a call to the ListenAndServe(). then just call waitGroup. Wait() at end of main() to wait for the goroutine to have finished its job.
You can easily cancel by messaging us on WhatsApp, Facebook Messenger or using the Live Chat on our website. You can also visit one of our GO outlets.
ListenAndServe() is blocking, and in your scenario, there are two of them, then try to put one of them in a goroutine. The idea is to separate the execution of those two web server initialization statements into separate goroutine.
Regarding graceful shutdown (introduced in Go 1.8), a bit more concrete example:
package main import ( "context" "io" "log" "net/http" "sync" "time" ) func startHttpServer(wg *sync.WaitGroup) *http.Server { srv := &http.Server{Addr: ":8080"} http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { io.WriteString(w, "hello world\n") }) go func() { defer wg.Done() // let main know we are done cleaning up // always returns error. ErrServerClosed on graceful close if err := srv.ListenAndServe(); err != http.ErrServerClosed { // unexpected error. port in use? log.Fatalf("ListenAndServe(): %v", err) } }() // returning reference so caller can call Shutdown() return srv } func main() { log.Printf("main: starting HTTP server") httpServerExitDone := &sync.WaitGroup{} httpServerExitDone.Add(1) srv := startHttpServer(httpServerExitDone) log.Printf("main: serving for 10 seconds") time.Sleep(10 * time.Second) log.Printf("main: stopping HTTP server") // now close the server gracefully ("shutdown") // timeout could be given with a proper context // (in real world you shouldn't use TODO()). if err := srv.Shutdown(context.TODO()); err != nil { panic(err) // failure/timeout shutting down the server gracefully } // wait for goroutine started in startHttpServer() to stop httpServerExitDone.Wait() log.Printf("main: done. exiting") }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With