readyz signals when the handler succeeds for the first time.

Co-authored-by: Dr. Stefan Schimanski <stefan.schimanski@gmail.com>
This commit is contained in:
Lukasz Szaszkiewicz 2021-06-30 11:04:44 +02:00
parent 93119f4503
commit ca108d109d

View File

@ -140,6 +140,12 @@ func InstallReadyzHandler(mux mux, checks ...HealthChecker) {
InstallPathHandler(mux, "/readyz", checks...) InstallPathHandler(mux, "/readyz", checks...)
} }
// InstallReadyzHandlerWithHealthyFunc is like InstallReadyzHandler, but in addition call firstTimeReady
// the first time /readyz succeeds.
func InstallReadyzHandlerWithHealthyFunc(mux mux, firstTimeReady func(), checks ...HealthChecker) {
InstallPathHandlerWithHealthyFunc(mux, "/readyz", firstTimeReady, checks...)
}
// InstallLivezHandler registers handlers for liveness checking on the path // InstallLivezHandler registers handlers for liveness checking on the path
// "/livez" to mux. *All handlers* for mux must be specified in // "/livez" to mux. *All handlers* for mux must be specified in
// exactly one call to InstallHandler. Calling InstallHandler more // exactly one call to InstallHandler. Calling InstallHandler more
@ -154,6 +160,12 @@ func InstallLivezHandler(mux mux, checks ...HealthChecker) {
// InstallPathHandler more than once for the same path and mux will // InstallPathHandler more than once for the same path and mux will
// result in a panic. // result in a panic.
func InstallPathHandler(mux mux, path string, checks ...HealthChecker) { func InstallPathHandler(mux mux, path string, checks ...HealthChecker) {
InstallPathHandlerWithHealthyFunc(mux, path, nil, checks...)
}
// InstallPathHandlerWithHealthyFunc is like InstallPathHandler, but calls firstTimeHealthy exactly once
// when the handler succeeds for the first time.
func InstallPathHandlerWithHealthyFunc(mux mux, path string, firstTimeHealthy func(), checks ...HealthChecker) {
if len(checks) == 0 { if len(checks) == 0 {
klog.V(5).Info("No default health checks specified. Installing the ping handler.") klog.V(5).Info("No default health checks specified. Installing the ping handler.")
checks = []HealthChecker{PingHealthz} checks = []HealthChecker{PingHealthz}
@ -172,7 +184,7 @@ func InstallPathHandler(mux mux, path string, checks ...HealthChecker) {
/* component = */ "", /* component = */ "",
/* deprecated */ false, /* deprecated */ false,
/* removedRelease */ "", /* removedRelease */ "",
handleRootHealth(name, checks...))) handleRootHealth(name, firstTimeHealthy, checks...)))
for _, check := range checks { for _, check := range checks {
mux.Handle(fmt.Sprintf("%s/%v", path, check.Name()), adaptCheckToHandler(check.Check)) mux.Handle(fmt.Sprintf("%s/%v", path, check.Name()), adaptCheckToHandler(check.Check))
} }
@ -209,8 +221,9 @@ func getExcludedChecks(r *http.Request) sets.String {
} }
// handleRootHealth returns an http.HandlerFunc that serves the provided checks. // handleRootHealth returns an http.HandlerFunc that serves the provided checks.
func handleRootHealth(name string, checks ...HealthChecker) http.HandlerFunc { func handleRootHealth(name string, firstTimeHealthy func(), checks ...HealthChecker) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var notifyOnce sync.Once
return func(w http.ResponseWriter, r *http.Request) {
excluded := getExcludedChecks(r) excluded := getExcludedChecks(r)
// failedVerboseLogOutput is for output to the log. It indicates detailed failed output information for the log. // failedVerboseLogOutput is for output to the log. It indicates detailed failed output information for the log.
var failedVerboseLogOutput bytes.Buffer var failedVerboseLogOutput bytes.Buffer
@ -246,6 +259,11 @@ func handleRootHealth(name string, checks ...HealthChecker) http.HandlerFunc {
return return
} }
// signal first time this is healthy
if firstTimeHealthy != nil {
notifyOnce.Do(firstTimeHealthy)
}
w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.Header().Set("Content-Type", "text/plain; charset=utf-8")
w.Header().Set("X-Content-Type-Options", "nosniff") w.Header().Set("X-Content-Type-Options", "nosniff")
if _, found := r.URL.Query()["verbose"]; !found { if _, found := r.URL.Query()["verbose"]; !found {
@ -255,7 +273,7 @@ func handleRootHealth(name string, checks ...HealthChecker) http.HandlerFunc {
individualCheckOutput.WriteTo(w) individualCheckOutput.WriteTo(w)
fmt.Fprintf(w, "%s check passed\n", name) fmt.Fprintf(w, "%s check passed\n", name)
}) }
} }
// adaptCheckToHandler returns an http.HandlerFunc that serves the provided checks. // adaptCheckToHandler returns an http.HandlerFunc that serves the provided checks.