Health Check
L'endpoint que tout le monde croit trivial — et qui, mal conçu, casse l'auto-healing infrastructure. Liveness, readiness, startup : trois questions différentes.
Problème
Un service EDI démarre en chargeant 200 Mo de schémas EDIFACT,
établit une connexion à Kafka et à Redis. Pendant ce warmup de 15s,
Kubernetes envoie un GET / qui renvoie 200 : le
Pod est marqué Ready et reçoit du trafic. Les premières requêtes
plantent en NPE « schémas non chargés ». Pire : en
production, un schéma corrompu fait planter le parser à chaque
requête, mais le process reste vivant — Kubernetes ne kill jamais
le Pod parce que /health répond toujours 200. Le Pod
est zombie.
Forces
- Plusieurs questions différentes : le process tourne-t-il ? Peut-il accepter du trafic maintenant ? A-t-il fini de démarrer ?
- L'orchestrateur agit différemment selon la réponse. Liveness fail → restart Pod. Readiness fail → retirer du LB. Startup fail → attendre encore.
- Le health doit être bon marché. Interrogé toutes les 5-10s par Pod. Pas de query DB lourde.
- Le health peut mentir. Si on teste « est-ce que je peux pinger Kafka », un partenaire externe down nous fait dire ready=false. Distinguer dépendance critique vs optionnelle.
Solution
Exposer trois endpoints distincts : /health/live (le process est vivant —
test minimal, ne touche aucune dépendance, juste « je peux
répondre à un HTTP »), /health/ready (prêt à recevoir du
trafic — vérifie dépendances critiques : DB, broker, schémas
chargés), /health/startup (démarrage
terminé — utile pour les apps lentes au boot). Format de
réponse : suivre l'IETF draft Health Check Response Format ou
Microsoft Health Endpoint. Sur Kubernetes : configurer livenessProbe, readinessProbe, startupProbe avec les bons paramètres
(periodSeconds, failureThreshold).
Trois endpoints distincts (RFC Health Check Response Format) :
GET /health/live → liveness
200 = "process vivant, ne pas kill"
503 = "process zombie, redémarrer"
GET /health/ready → readiness
200 = "prêt à recevoir du trafic"
503 = "warmup en cours / dépendance down / drain"
→ si 503, le LB retire le Pod du round-robin
GET /health/startup → startup
200 = "initialisation terminée"
503 = "encore en train de charger les schémas EDIFACT"
→ bloque les autres probes pendant le démarrage
Réponse JSON RFC :
{
"status": "pass" | "warn" | "fail",
"version": "1.4.2",
"checks": {
"kafka": { "status": "pass", "time": "2026-05-16T08:30:00Z" },
"redis": { "status": "pass" },
"as2.walmart": { "status": "warn", "observedValue": 12s }
}
}
Implémentation EDI
Cas concret : service parser EDIFACT en Spring Boot avec
Spring Boot Actuator. /actuator/health/liveness renvoie
200 sauf si le process est dans un état non-recoverable
(OutOfMemoryError, deadlock détecté). /actuator/health/readiness
vérifie : connexion Kafka producer, connexion Redis cache,
schémas EDIFACT D.96A/D.01B/D.24A chargés, état du Circuit Breaker
vers Walmart (si ouvert depuis > 30 min → warn, sinon pass). /actuator/health/startup renvoie 503 tant que les
schémas ne sont pas chargés (jusqu'à 90s). Sur Kubernetes, startupProbe.failureThreshold=30 × periodSeconds=5s =
grace period 2,5 min avant abandon. Pour PEPPOL Access Point, le
health doit aussi vérifier la rotation des certificats AS4 — un cert
expiré rend l'AP inutilisable même si le process tourne.
Anti-patterns
- Un seul
/health. Mélanger liveness et readiness signifie qu'une dépendance externe down fait restart le Pod en boucle (qui n'aide en rien). - Health qui exécute du business logic. « Je teste en envoyant un INVOIC réel à Walmart » : pollue le log audit du partenaire, peut violer SLA.
- Health caché derrière auth. Le kubelet ne peut pas s'authentifier facilement. Exposer en network policy interne sans auth.
- Health qui interroge toutes les dépendances en cascade. Si le check d'une dépendance prend 30s, le health timeout, le Pod est restart à tort.
- Cascade de readiness. Service A ready=false si service B ready=false : une panne se propage en arrière. Distinguer dépendance critique (échec si absente) vs dégradation gracieuse.
Patterns liés
- Circuit Breaker — l'état du breaker peut influencer la readiness.
- Circuit Breaker Half-Open — la requête-test peut être un health check.
- Control Bus — le canal admin peut consommer les events de health.
- Test Message — le canari synthétique est un health check métier.
- Wire Tap — observabilité passive, complémentaire du health actif.
Sources
- Microsoft Architecture Center — Health Endpoint Monitoring pattern. learn.microsoft.com — Health endpoint
- Kubernetes docs — Configure Liveness, Readiness and Startup Probes. kubernetes.io — Probes
- IETF draft — Health Check Response Format for HTTP APIs (Nottingham, Carrasco). Format JSON canonique. ietf.org — API health check
- Spring Boot Actuator — HealthIndicator. L'implémentation Java idiomatique. spring.io — Actuator health
- Newman S. — Building Microservices, O'Reilly 2e éd. 2021. Chap. « Monitoring » développe les différences entre liveness et readiness.