package web import ( "fmt" "net/http" "time" "github.com/go-chi/chi" log "scm.yoorie.de/go-lib/gelf" ) /* healthChecker Class */ type healthChecker struct { message string healthy bool lastChecked time.Time period int ticker *time.Ticker done chan bool //This is the healtchcheck you will have to provide. checkFunc func() (bool, string) } func newHealthChecker(checkFunction func() (bool, string)) *healthChecker { hc := &healthChecker{} hc.checkFunc = checkFunction return hc } func (h *healthChecker) start(checkPeriodInSeconds int) { h.period = checkPeriodInSeconds h.message = "service starting" h.healthy = false h.doCheck() h.ticker = time.NewTicker(time.Second * time.Duration(h.period)) h.done = make(chan bool) go func() { for { select { case <-h.done: return case <-h.ticker.C: h.doCheck() } } }() } func (h *healthChecker) stop() { h.ticker.Stop() h.done <- true log.Debug("Health checker stopped.") } //internal function to process the health check func (h *healthChecker) doCheck() { var msg string h.healthy, msg = h.checkFunc() if !h.healthy { h.message = msg } else { h.message = "" } h.lastChecked = time.Now() } // Routes add routes for liveness and readyness probes func (h *healthChecker) Routes() *chi.Mux { router := chi.NewRouter() router.Get("/healthz", h.healthyEndpoint) router.Get("/readyz", h.readinessEndpoint) return router } /* GetHealthyEndpoint is this service healthy */ func (h *healthChecker) healthyEndpoint(response http.ResponseWriter, req *http.Request) { t := time.Now() if t.Sub(h.lastChecked) > (time.Second * time.Duration(2*h.period)) { h.healthy = false h.message = "Healthcheck not running" } response.Header().Add("Content-Type", "application/json") if h.healthy { response.WriteHeader(http.StatusOK) message := fmt.Sprintf(`{ "message": "service up and running", "lastCheck": "%s" }`, h.lastChecked.String()) response.Write([]byte(message)) } else { response.WriteHeader(http.StatusServiceUnavailable) message := fmt.Sprintf(`{ "message": "service is unavailable: %s", "lastCheck": "%s" }`, h.message, h.lastChecked.String()) response.Write([]byte(message)) } } /* GetReadinessEndpoint is this service ready for taking requests */ func (h *healthChecker) readinessEndpoint(response http.ResponseWriter, req *http.Request) { response.Header().Add("Content-Type", "application/json") response.WriteHeader(http.StatusOK) response.Write([]byte(`{ "message": "service started" }`)) }