Skip to content

Instantly share code, notes, and snippets.

@klrkdekira
Created August 23, 2016 14:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save klrkdekira/90be7ace5c0fb7f80b98ff60ed21579c to your computer and use it in GitHub Desktop.
Save klrkdekira/90be7ace5c0fb7f80b98ff60ed21579c to your computer and use it in GitHub Desktop.
package main
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"sync"
)
type RobinHood struct {
counter int
mu *sync.Mutex
handlers []http.Handler
}
func (rh *RobinHood) ServeHTTP(w http.ResponseWriter, r *http.Request) {
rh.mu.Lock()
// Fail to do this will lock the server forever
defer rh.mu.Unlock()
rh.handlers[rh.counter].ServeHTTP(w, r)
rh.counter = (rh.counter + 1) % len(rh.handlers)
}
func (rh *RobinHood) AddHandler(handler http.Handler) {
rh.mu.Lock()
defer rh.mu.Unlock()
rh.handlers = append(rh.handlers, handler)
}
func newRobinHood(handlers ...http.Handler) *RobinHood {
return &RobinHood{
counter: 0,
mu: &sync.Mutex{},
handlers: handlers,
}
}
// boilerplate to create a closure Handler
func newHandler(msg string) http.Handler {
mux := http.NewServeMux()
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
fmt.Fprintf(w, "Hello, from %s!", msg)
})
return mux
}
func main() {
one := newHandler("One")
two := newHandler("Two")
three := newHandler("Three")
// Bootstrapping the handler
handler := newRobinHood(one, two, three)
server := &http.Server{
Handler: handler,
Addr: "127.0.0.1:9090",
}
// Starts webserver in background
go func() {
if err := server.ListenAndServe(); err != nil {
log.Fatal(err)
}
}()
fmt.Println("Started web server")
// HTTP Request
req, err := http.NewRequest("GET", "http://127.0.0.1:9090/", nil)
if err != nil {
log.Fatal(err)
}
// Always close the connection
req.Close = true
requestCount := 5
for i := 0; i < requestCount; i++ {
fmt.Printf("Calling server... (%d/%d)\n", i+1, requestCount)
lookup(req)
}
fmt.Println("Adding new handler")
handler.AddHandler(newHandler("Mystery Intruder"))
for i := 0; i < requestCount; i++ {
fmt.Printf("Calling server... (%d/%d)\n", i+1, requestCount)
lookup(req)
}
fmt.Println("All done, bye!")
}
func lookup(req *http.Request) {
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
// Always close an io operation
defer resp.Body.Close()
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Received response, %s\n", b)
}
$ go run basic_http_round_robin_bonus.go
Started web server
Calling server... (1/5)
Received response, Hello, from One!
Calling server... (2/5)
Received response, Hello, from Two!
Calling server... (3/5)
Received response, Hello, from Three!
Calling server... (4/5)
Received response, Hello, from One!
Calling server... (5/5)
Received response, Hello, from Two!
Adding new handler
Calling server... (1/5)
Received response, Hello, from Three!
Calling server... (2/5)
Received response, Hello, from Mystery Intruder!
Calling server... (3/5)
Received response, Hello, from One!
Calling server... (4/5)
Received response, Hello, from Two!
Calling server... (5/5)
Received response, Hello, from Three!
All done, bye!
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment