Health check
- Go course
- Advanced
- Lesson 63/68
- 4 min
Learn to write a /healthz health endpoint.
Health checks
Orchestrators ask two questions: liveness — is the process alive? (restart it if not) and readiness — is it ready for traffic? (is the database connected, is warm-up done?).
mux.HandleFunc("GET /livez", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("ok"))
})
mux.HandleFunc("GET /readyz", func(w http.ResponseWriter, r *http.Request) {
if err := db.PingContext(r.Context()); err != nil {
http.Error(w, "db yok", http.StatusServiceUnavailable)
return
}
w.Write([]byte("ok"))
})Not ready while shutting down
During graceful shutdown the service first flips readiness to "not ready", waits for the load balancer to stop sending traffic, then finishes in-flight requests and exits. An atomic flag is enough for this:
var hazir atomic.Bool
hazir.Store(true)
// on SIGTERM
hazir.Store(false)
time.Sleep(5 * time.Second)
srv.Shutdown(ctx)Practice Readiness endpoint
Declare var hazir atomic.Bool. The /readyz handler returns 503 if the flag is false and 200 if true. Send two requests — with the flag false and after setting it true — and print both codes on one line.
Starter code
package main
import (
"fmt"
"net/http"
"net/http/httptest"
"sync/atomic"
)
func main() {
// buraya yaz
}Sample solution
package main
import (
"fmt"
"net/http"
"net/http/httptest"
"sync/atomic"
)
var hazir atomic.Bool
func readyz(w http.ResponseWriter, r *http.Request) {
if !hazir.Load() {
http.Error(w, "hazır değil", http.StatusServiceUnavailable)
return
}
w.Write([]byte("ok"))
}
func istek() int {
rec := httptest.NewRecorder()
readyz(rec, httptest.NewRequest("GET", "/readyz", nil))
return rec.Code
}
func main() {
once := istek()
hazir.Store(true)
fmt.Println(once, istek())
}Expected output
503 200
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 What can happen if the liveness check also checks the database?
- The application speeds up
- A brief database outage restarts every pod for nothing Correct answer
- It becomes safer
- Nothing changes
Explanation: Restarting doesn't fix a database problem; dependency checks go in readiness, liveness looks at the process itself.
2 Unavailable code
http.Error(w, "hazır değil", http.____)
http.Error(w, "hazır değil", http.StatusServiceUnavailable)
Explanation: 503 Service Unavailable reports that the service isn't ready for traffic right now.
3 Check and question
| Term | Meaning |
|---|---|
/livez |
Is the process alive? |
/readyz |
Can it take traffic? |
503 |
Not ready |
atomic.Bool |
Safe ready flag |