Interview Prep Zoneby CuriouserLabs

Question 2 of 5 · staff level

Liveness vs readiness: how do you design health checks for Kubernetes, and what goes into a custom HealthIndicator?

🎤 Say this first

Liveness answers 'should this process be restarted?' — only internal, unrecoverable states (broken event loops, poisoned state); it must not check dependencies, or a DB blip triggers fleet-wide restart storms. Readiness answers 'should traffic be routed here?' — may include required dependencies and lifecycle state (warm-up, graceful shutdown drain). Boot maps these to /actuator/health/liveness|readiness via probe groups and manages the state transitions with the container lifecycle. Custom HealthIndicators: cheap, cached/async for slow checks, and classified into the right group — most belong in readiness or in neither (dashboards instead).

The full picture

Probe groups + a disciplined custom indicator
management:
  endpoint.health.probes.enabled: true
  endpoint.health.group:
    readiness:
      include: readinessState, db, kafkaConsumerLag   # required deps only
    liveness:
      include: livenessState                          # NOTHING external!

@Component("kafkaConsumerLag")
class ConsumerLagHealth implements HealthIndicator {
    private volatile Health cached = Health.up().build();   // refreshed async
    @Scheduled(fixedDelay = 10_000)
    void refresh() {                                        // probe never blocks
        long lag = lagMonitor.maxLag();
        cached = lag < 10_000 ? Health.up().withDetail("lag", lag).build()
                              : Health.outOfService().withDetail("lag", lag).build();
    }
    @Override public Health health() { return cached; }
}
  • The cascade failure to name: DB in liveness → DB hiccup → kubelet restarts every pod → connection storm on recovering DB → longer outage. Liveness checks dependencies is the #1 probe anti-pattern.
  • Readiness nuance: only hard dependencies (can't do anything without the DB); optional dependencies (recommendation service) belong in degraded-mode logic + alerts, not readiness — or you turn partial degradation into full outage.
  • Timing: probes run every few seconds from kubelet — health() must be O(cached-read); Boot's AvailabilityState events let graceful shutdown flip readiness before stopping the server (drain window).
  • Startup probes (or initialDelay) protect slow-booting JVMs from liveness-killing them mid-warmup.

🔄 Likely follow-up questions

  • How does Boot's graceful shutdown sequence readiness-flip, drain and pool close?
  • Where does a circuit-breaker's state belong — readiness, metrics, or neither?
  • How do you test probe behavior before an incident tests it for you?