diff --git a/pkg/proxy/healthcheck/proxier_health.go b/pkg/proxy/healthcheck/proxier_health.go index ca3a9acd6d7..77ea1542d52 100644 --- a/pkg/proxy/healthcheck/proxier_health.go +++ b/pkg/proxy/healthcheck/proxier_health.go @@ -44,6 +44,7 @@ type ProxierHealthUpdater interface { } var _ ProxierHealthUpdater = &proxierHealthServer{} +var zeroTime = time.Time{} // proxierHealthServer returns 200 "OK" by default. It verifies that the delay between // QueuedUpdate() calls and Updated() calls never exceeds healthTimeout. @@ -57,8 +58,8 @@ type proxierHealthServer struct { recorder events.EventRecorder nodeRef *v1.ObjectReference - lastUpdated atomic.Value - lastQueued atomic.Value + lastUpdated atomic.Value + oldestPendingQueued atomic.Value } // NewProxierHealthServer returns a proxier health http server. @@ -80,12 +81,14 @@ func newProxierHealthServer(listener listener, httpServerFactory httpServerFacto // Updated updates the lastUpdated timestamp. func (hs *proxierHealthServer) Updated() { + hs.oldestPendingQueued.Store(zeroTime) hs.lastUpdated.Store(hs.clock.Now()) } // QueuedUpdate updates the lastQueued timestamp. func (hs *proxierHealthServer) QueuedUpdate() { - hs.lastQueued.Store(hs.clock.Now()) + // Set oldestPendingQueued only if it's currently zero + hs.oldestPendingQueued.CompareAndSwap(zeroTime, hs.clock.Now()) } // Run starts the healthz HTTP server and blocks until it exits. @@ -117,9 +120,9 @@ type healthzHandler struct { } func (h healthzHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { - var lastQueued, lastUpdated time.Time - if val := h.hs.lastQueued.Load(); val != nil { - lastQueued = val.(time.Time) + var oldestPendingQueued, lastUpdated time.Time + if val := h.hs.oldestPendingQueued.Load(); val != nil { + oldestPendingQueued = val.(time.Time) } if val := h.hs.lastUpdated.Load(); val != nil { lastUpdated = val.(time.Time) @@ -128,15 +131,11 @@ func (h healthzHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { healthy := false switch { - case lastUpdated.IsZero(): + case oldestPendingQueued.IsZero(): // The proxy is healthy while it's starting up - // TODO: this makes it useless as a readinessProbe. Consider changing - // to only become healthy after the proxy is fully synced. + // or the proxy is fully synced. healthy = true - case lastUpdated.After(lastQueued): - // We've processed all updates - healthy = true - case currentTime.Sub(lastQueued) < h.hs.healthTimeout: + case currentTime.Sub(oldestPendingQueued) < h.hs.healthTimeout: // There's an unprocessed update queued, but it's not late yet healthy = true } @@ -147,14 +146,12 @@ func (h healthzHandler) ServeHTTP(resp http.ResponseWriter, req *http.Request) { resp.WriteHeader(http.StatusServiceUnavailable) } else { resp.WriteHeader(http.StatusOK) - // In older releases, the returned "lastUpdated" time indicated the last // time the proxier sync loop ran, even if nothing had changed. To // preserve compatibility, we use the same semantics: the returned // lastUpdated value is "recent" if the server is healthy. The kube-proxy // metrics provide more detailed information. lastUpdated = currentTime - } fmt.Fprintf(resp, `{"lastUpdated": %q,"currentTime": %q}`, lastUpdated, currentTime) }