Saturday, March 12, 2016

Many Servers in One, with Go.

I’m still fiddling with a web server idea, currently trying my umpteenth version of it in Go. One of the things I want to do is serve a bunch of different things from one binary; they would usually live behind Nginx anyway, and I like the simplicity of serving a bunch of (somewhat) dynamic, small sites from a single program.

So, how does one do it? Why, one does it with Goroutines!

I had expected that to be the answer, but even then I was surprised at the simplicity of this solution. You don’t even need channels, since http.ListenAndServe is a blocking call if it’s not in a Goroutine.

Here’s the code, which should be self-explanatory.

// multiserve - serve multiple web sites from one Go binary.
// ----------
// Just a demo for now. (C) Kevin Frost, github: biztos;
// MIT license if you like.
package main
import (
"fmt"
"log"
"net/http"
)
type Server struct {
Name string
Mux *http.ServeMux
Port int
}
func (s *Server) Serve() {
fmt.Printf("%s server listening on port %d.\n", s.Name, s.Port)
portStr := fmt.Sprintf(":%d", s.Port)
http.ListenAndServe(portStr, s.Mux)
}
func NewServer(name string, port int) *Server {
homeHandler := func(w http.ResponseWriter, r *http.Request) {
log.Printf("%s shall serve!\n", name)
msg := fmt.Sprintf("Hello %s World!\n", name)
w.Write([]byte(msg))
}
mux := http.NewServeMux()
mux.HandleFunc("/", homeHandler)
return &Server{
Name: name,
Port: port,
Mux: mux,
}
}
func main() {
// Set up a router for each server. Here we just use two but
// you could probably have lots and lots.
servers := []*Server{
NewServer("Foo", 8001),
NewServer("Bar", 8002),
}
// Start them using goroutines, but *not* for the last one:
final := len(servers) - 1
for i, s := range servers {
if i == final {
s.Serve()
} else {
go s.Serve()
}
}
}
view raw multiserve.go hosted with ❤ by GitHub