diff options
Diffstat (limited to 'main.go')
-rw-r--r-- | main.go | 58 |
1 files changed, 39 insertions, 19 deletions
@@ -5,46 +5,73 @@ import ( "log" "net/http" "os" + "sync" "time" ) +// Globals are generally discouraged, but this is a very simple program, and we +// are designing with concurrent access in mind. + +// Creating a custom struct with a lock, so we can lock access to the object +type status struct { + value int + sync.Mutex +} + // ReadyValue indiciates the program is ready to receive traffic -var ReadyValue = http.StatusOK +var ReadyValue = status{value: http.StatusOK} // LiveValue indiciates the program is alive and should not be terminated -var LiveValue = http.StatusOK +var LiveValue = status{value: http.StatusOK} var hostname string func makeNotReady(w http.ResponseWriter, r *http.Request) { - ReadyValue = http.StatusBadRequest + // Lock access to the variable, then set our global ReadyValue to a failing + // value before sending the response + ReadyValue.Lock() + ReadyValue.value = http.StatusBadRequest + ReadyValue.Unlock() w.Header().Set("responding-pod", hostname) fmt.Fprintf(w, "%s", "Set Readiness Value to a failure state") } +// Hitting this endpoint (by any means) will func makePodReady(w http.ResponseWriter, r *http.Request) { - ReadyValue = http.StatusOK + ReadyValue.Lock() + ReadyValue.value = http.StatusOK + ReadyValue.Unlock() w.Header().Set("responding-pod", hostname) fmt.Fprintf(w, "%s", "Set Readiness Value to successful (OK) state") } +// This function guarantees Kubernetes will kill the pod func killMe(w http.ResponseWriter, r *http.Request) { - LiveValue = http.StatusBadRequest + LiveValue.Lock() + LiveValue.value = http.StatusBadRequest + LiveValue.Unlock() w.Header().Set("responding-pod", hostname) fmt.Fprintf(w, "%s", "Set Liveness Value to a failure state") } +// Provides Ready state to Kubernetes for receiving/stopping traffic func readinessCheck(w http.ResponseWriter, r *http.Request) { w.Header().Set("responding-pod", hostname) - http.Error(w, "Responding with ReadyValue", ReadyValue) + ReadyValue.Lock() + http.Error(w, "Responding with ReadyValue", ReadyValue.value) + ReadyValue.Unlock() } +// Endpoint checked internally by Kubernetes func livenessCheck(w http.ResponseWriter, r *http.Request) { w.Header().Set("responding-pod", hostname) - http.Error(w, "Responding with LiveValue", LiveValue) + LiveValue.Lock() + http.Error(w, "Responding with LiveValue", LiveValue.value) + LiveValue.Unlock() } +// The default endpoint func rootHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("responding-pod", hostname) fmt.Fprintf(w, "%s", "I'm serving traffic!") @@ -54,21 +81,14 @@ func main() { // Force log output to stdout for Docker log.SetOutput(os.Stdout) - // Configurable delay for startup - var delay = (1 * time.Second) - if os.Getenv("APPDELAY") != "" { - var err error - delay, err = time.ParseDuration(os.Getenv("APPDELAY")) - if err != nil { - log.Fatalf("Failed to parse time duration: %v", err) - } - } - time.Sleep(delay) - // Finish startup hostname, _ = os.Hostname() log.Println("Service started on port 80") + // Set up a custom mutex to add custom handlers. [Note] this level of breakout + // is not required, as we could reasonably compact this into a single call, + // but would lose some readability. This also makes it easy for us to use a + // custom muxer (e.g. gorillamux), custom server, etc mux := http.NewServeMux() mux.HandleFunc("/", rootHandler) mux.HandleFunc("/ping", livenessCheck) @@ -84,8 +104,8 @@ func main() { WriteTimeout: 3 * time.Second, } + // Actually run our server if err := server.ListenAndServe(); err != nil { log.Fatalln(err) } - } |