I'm a novice Go programmer.
I am writing a web application and I need the server to wait until the active requests are made before closing.
I wrote a handler that waits 5 seconds to answer. If I make a request and stop the server (before the 5 seconds) I get an "Unable to connect" error.
There is a way to stop listen new requests and wait to active requests get done?
Here my example
func main() {
log.Infof("Starting (PID %d)...", os.Getpid())
stop := make(chan os.Signal, 1)
signal.Notify(stop, syscall.SIGTERM)
signal.Notify(stop, syscall.SIGINT)
listenAt := "127.0.0.1:8000"
r := newRouter()
h := &http.Server{Addr: listenAt, Handler: r}
go func() {
log.Info("Serving on http://", listenAt)
if err := h.ListenAndServe(); err != nil {
log.Fatal(err)
}
}()
<-stop
log.Info("Stoping ...")
h.Shutdown(context.Background())
log.Info("Bye :)")
}
Example Handler
func handler(w http.ResponseWriter, r *http.Request) {
time.Sleep(5 * time.Second)
log.Info("new request")
fmt.Fprintf(w, "Hola!")
}
Full example @ https://gist.github.com/nachopro/d80fa71ae49527e1ddcaf359b4ff488b
one way is to narrow down your max connection to 1 by:
l, err := net.Listen("tcp", ":8000")
if err != nil {
log.Fatalf("Listen: %v", err)
}
defer l.Close()
l = netutil.LimitListener(l, 1)
log.Fatal(http.Serve(l, nil))
another way is using a global variable:
package main
import (
"net/http"
"sync/atomic"
"fmt"
)
var toggle *int32
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
func handler(w http.ResponseWriter, r *http.Request) {
val := atomic.LoadInt32(toggle)
if val != 0 {
fmt.Fprintln(w, "Not Valid!")
w.WriteHeader(http.StatusForbidden)
return
}
atomic.StoreInt32(toggle, 1)
// do stuff
w.WriteHeader(http.StatusOK)
}
func init (){
atomic.StoreInt32(toggle, int32(0))
}
**notice both ways works for single node servers and does not work in distributed systems, solution for that is using cache servers like redis etc.
Thanks to this blog entry and their example I found this issue and their solution. I saw that my problem isn't related to net/http module!
The real problem is the log.Fatal(err)
inside go func()
, changing it to log.Info(err)
does not abort the shutdown process.
go func() {
log.Info("Serving on http://", listenAt)
if err := h.ListenAndServe(); err != nil {
// log.Fatal(err)
log.Info(err)
}
}()