106 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			106 lines
		
	
	
		
			2.5 KiB
		
	
	
	
		
			Go
		
	
	
	
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" }`))
 | 
						|
}
 |