-
Star
(139)
You must be signed in to star a gist -
Fork
(35)
You must be signed in to fork a gist
-
-
Save peterhellberg/38117e546c217960747aacf689af3dc2 to your computer and use it in GitHub Desktop.
package main | |
import ( | |
"context" | |
"log" | |
"net/http" | |
"os" | |
"os/signal" | |
"time" | |
) | |
type Server struct { | |
logger *log.Logger | |
mux *http.ServeMux | |
} | |
func NewServer(options ...func(*Server)) *Server { | |
s := &Server{ | |
logger: log.New(os.Stdout, "", 0), | |
mux: http.NewServeMux(), | |
} | |
for _, f := range options { | |
f(s) | |
} | |
s.mux.HandleFunc("/", s.index) | |
return s | |
} | |
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) { | |
s.mux.ServeHTTP(w, r) | |
} | |
func (s *Server) index(w http.ResponseWriter, r *http.Request) { | |
s.logger.Println("GET /") | |
w.Write([]byte("Hello, World!")) | |
} | |
func main() { | |
stop := make(chan os.Signal, 1) | |
signal.Notify(stop, os.Interrupt) | |
logger := log.New(os.Stdout, "", 0) | |
addr := ":" + os.Getenv("PORT") | |
if addr == ":" { | |
addr = ":2017" | |
} | |
s := NewServer(func(s *Server) { s.logger = logger }) | |
h := &http.Server{Addr: addr, Handler: s} | |
go func() { | |
logger.Printf("Listening on http://0.0.0.0%s\n", addr) | |
if err := h.ListenAndServe(); err != nil { | |
logger.Fatal(err) | |
} | |
}() | |
<-stop | |
logger.Println("\nShutting down the server...") | |
ctx, _ := context.WithTimeout(context.Background(), 5*time.Second) | |
h.Shutdown(ctx) | |
logger.Println("Server gracefully stopped") | |
} |
Hi, great contribution.
There is one thing that could make it more complete in my opinion.
Everywhere this code is, it will always print "Listening on http://...." in the console, even if ListenAndServe()
was unable to start actually listening.
log.Printf("Listening on http://0.0.0.0%s\n", hs.Addr)
if err := hs.ListenAndServe(); err != http.ErrServerClosed {
log.Fatal(err)
}
If you start 1 server, you'll see this in the console:
Listening on http://0.0.0.0:2017
If you start a 2nd server without shutting down the 1st one, you will see this in the console:
Listening on http://0.0.0.0:2017
panic... listen tcp :2017: bind: address already in use
So it first shows "Listening on http://..." however this never actually happened.
I'm not a go expert, is there a way to implement this?
-- UPDATE
Apparently using http.Listen
and http.Serve
individually, it is possible to catch a port in use error (or any other error while trying to listen to a tcp network) before assuming the server is listening.
Source: https://stackoverflow.com/a/48250354/194630
listener, err := net.Listen("tcp", ":"+config.Port)
if err != nil {
log.Fatal(err)
}
done := make(chan bool)
go server.Serve(listener)
// Log server started
log.Printf("Server started at port %v", config.Port)
<-done
@peterhellberg Thanks for sharing this!