Guides 7 min de lecture

Comment créer un endpoint de health check (et le surveiller)

Un endpoint de health check indique aux moniteurs et aux load balancers si votre application peut servir des requêtes. Quoi vérifier, comment le garder rapide et sûr, du code pour Laravel, Express et Flask, et comment le surveiller.

Un endpoint de health check est une URL, généralement /health, qui indique à un moniteur ou à un load balancer si votre application peut servir des requêtes. Il exécute quelques vérifications rapides sur ce dont l’application dépend, comme la base de données, le cache et l’espace disque libre, et répond par HTTP 200 et {« status »: »ok »} quand tout fonctionne, ou par HTTP 503 et le nom de la vérification en échec quand ce n’est pas le cas. Gardez-le rapide, peu coûteux, hors cache et sans secrets, puis pointez dessus un moniteur de disponibilité qui valide la réponse, pas seulement le code de statut.

Ce guide couvre la différence entre liveness et readiness, ce qu’il faut vérifier, le format de réponse, des exemples fonctionnels en PHP avec Laravel, Node avec Express et Python avec Flask, et la façon de surveiller l’endpoint une fois en place.

Pourquoi la page d’accueil n’est pas un health check

La plupart des équipes commencent par surveiller la page d’accueil. C’est une première étape raisonnable, mais la page d’accueil est souvent servie depuis un CDN ou un cache de pages : elle continue de répondre 200 alors que la base de données est en panne et que plus personne ne peut se connecter ni payer. Un endpoint dédié contourne le cache et sollicite directement les dépendances. Il vous donne aussi une URL unique et prévisible, avec une réponse courte et stable, facile à valider.

Liveness ou readiness

Les plateformes de conteneurs comme Kubernetes divisent la santé en deux questions, et cette distinction est utile partout :

Liveness : le processus est-il vivant et non bloqué ? Sinon, redémarrez-le. Un contrôle de liveness ne doit pas tester la base de données ni d’autres services. Si la base tombe et que toutes les instances de l’application échouent à leur contrôle de liveness, la plateforme les redémarre toutes, ce qui ne répare pas la base et ralentit la reprise.

Readiness : cette instance peut-elle servir de vraies requêtes en ce moment ? Sinon, cessez de lui envoyer du trafic. C’est ici que les vérifications des dépendances ont leur place.

Une organisation courante : /livez ou /up pour la liveness, qui renvoie 200 tant que l’application démarre, et /health ou /readyz pour la readiness. Pour la surveillance de disponibilité externe, c’est l’endpoint de readiness qui compte, car il répond à la question qui intéresse vos clients : l’application fonctionne-t-elle ?

Ce qu’il faut vérifier

Vérifiez les dépendances sans lesquelles une requête normale échouerait, et rien de plus :

Base de données : exécutez SELECT 1 sur le même pool de connexions que celui de l’application. Cela prouve que le serveur est joignable et accepte les requêtes.

Cache ou stockage des sessions : écrivez puis lisez une clé à courte durée de vie dans Redis ou Memcached. Si les sessions y sont stockées, la connexion en dépend.

Disque : vérifiez l’espace libre sur le volume où l’application écrit, pour les fichiers envoyés, les logs ou les sessions. Échouez quand il passe sous une marge, par exemple 10 %.

File d’attente : vérifiez que le backend de la file répond et, éventuellement, que la plus ancienne tâche en attente ne dépasse pas une limite que vous choisissez. Un arriéré qui grossit signifie que les workers se sont arrêtés.

Méfiez-vous des API tierces. Si votre endpoint appelle un prestataire de paiement à chaque contrôle et que ce prestataire est lent, votre health check échoue alors que votre propre application va bien, et un load balancer peut retirer toutes les instances de la rotation. Surveillez plutôt les services tiers avec leurs propres moniteurs, pour qu’une alerte vous dise de qui vient le problème. La surveillance des services tiers d’Uptimecheck suit les pages de statut de 31 services comme Klarna, Swish, Shopify, Cloudflare et OpenAI, ou de n’importe quelle page hébergée sur Statuspage.

Le garder rapide et peu coûteux

Un health check tourne chaque minute depuis chaque moniteur et chaque load balancer, jour et nuit. Il ne doit jamais devenir ce qui surcharge l’application.

Donnez à chaque vérification de dépendance son propre délai d’attente court, par exemple une ou deux secondes, pour qu’un service bloqué ne bloque pas l’endpoint.

Exécutez les vérifications en parallèle quand votre langage le permet facilement.

Utilisez des requêtes triviales. Ne comptez jamais les lignes d’une grande table et ne lancez jamais de rapport.

Si de nombreux outils de contrôle sollicitent l’endpoint, mettez le résultat en cache en mémoire pendant quelques secondes.

Envoyez Cache-Control: no-store et excluez le chemin des caches de pages et des CDN, pour ne jamais voir un « ok » en cache.

Évitez les sessions, les cookies et les middlewares d’authentification dont l’endpoint n’a pas besoin.

Ne divulguez pas de secrets

Un endpoint de santé public est visible par quiconque devine /health. Renvoyez le nom et l’état de chaque vérification, et rien d’autre. N’incluez ni messages d’exception, ni chaînes de connexion, ni noms d’hôtes, ni adresses IP internes, ni versions de logiciels, ni variables d’environnement. Consignez plutôt l’erreur détaillée dans les logs du serveur. Si vous voulez une vue de diagnostic plus riche, placez-la sur un chemin séparé derrière une authentification ou réservez-la à votre réseau interne.

Format de réponse et codes de statut

Gardez un JSON court et stable :

{
« status »: « ok »,
« checks »: {
« database »: « ok »,
« cache »: « ok »,
« disk »: « ok »,
« queue »: « ok »
}
}

Quand une vérification échoue, mettez sa valeur à « fail », passez le statut global à « fail » et changez le code de statut HTTP :

200 OK quand toutes les vérifications obligatoires passent.

503 Service Unavailable quand une vérification obligatoire échoue. C’est le code qu’attendent les load balancers et les moniteurs pour « temporairement incapable de servir ».

Éventuellement, 200 avec « status »: »degraded » pour une dépendance facultative en panne alors que le cœur fonctionne encore. Décidez dès le départ quelles vérifications sont obligatoires.

Évitez de renvoyer 200 avec « status »: »fail » dans le corps. Beaucoup d’outils ne lisent que le code de statut. Consultez les codes de statut HTTP pour la surveillance pour savoir comment chaque code est généralement traité.

Exemple : PHP et Laravel

Les versions récentes de Laravel fournissent une route /up simple qui confirme que l’application démarre, ce qui fait un bon contrôle de liveness. Pour la readiness, ajoutez une route qui vérifie les dépendances :

use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Route;

Route::get(‘/health’, function () {
$checks = [];

try {
DB::select(‘SELECT 1’);
$checks[‘database’] = ‘ok’;
} catch (\Throwable $e) {
report($e);
$checks[‘database’] = ‘fail’;
}

try {
Cache::put(‘health-check’, ‘ok’, 10);
$checks[‘cache’] = Cache::get(‘health-check’) === ‘ok’ ? ‘ok’ : ‘fail’;
} catch (\Throwable $e) {
report($e);
$checks[‘cache’] = ‘fail’;
}

$path = storage_path();
$checks[‘disk’] = disk_free_space($path) / disk_total_space($path) > 0.10 ? ‘ok’ : ‘fail’;

$healthy = ! in_array(‘fail’, $checks, true);

return response()
->json([‘status’ => $healthy ? ‘ok’ : ‘fail’, ‘checks’ => $checks], $healthy ? 200 : 503)
->header(‘Cache-Control’, ‘no-store’);
});

Enregistrez-la en dehors des groupes de middlewares qui démarrent des sessions, et définissez un délai de connexion court pour la base de données dans votre configuration.

Exemple : Node et Express

const withTimeout = (promise, ms) =>
Promise.race([
promise,
new Promise((_, reject) => setTimeout(() => reject(new Error(‘timeout’)), ms)),
]);

const check = (fn) => withTimeout(fn(), 2000).then(() => ‘ok’, () => ‘fail’);

app.get(‘/health’, async (req, res) => {
const [database, cache] = await Promise.all([
check(() => pool.query(‘SELECT 1’)),
check(() => redis.ping()),
]);

const checks = { database, cache };
const healthy = Object.values(checks).every((v) => v === ‘ok’);

res
.set(‘Cache-Control’, ‘no-store’)
.status(healthy ? 200 : 503)
.json({ status: healthy ? ‘ok’ : ‘fail’, checks });
});

Les vérifications s’exécutent en parallèle, chacune limitée à deux secondes : l’endpoint répond donc en deux secondes environ, même quand une dépendance est bloquée.

Exemple : Python et Flask

import shutil
from flask import jsonify
from sqlalchemy import text

@app.get(« /health »)
def health():
checks = {}

try:
db.session.execute(text(« SELECT 1 »))
checks[« database »] = « ok »
except Exception:
app.logger.exception(« health: database »)
checks[« database »] = « fail »

usage = shutil.disk_usage(« / »)
checks[« disk »] = « ok » if usage.free / usage.total > 0.10 else « fail »

healthy = all(value == « ok » for value in checks.values())
body = {« status »: « ok » if healthy else « fail », « checks »: checks}
return jsonify(body), 200 if healthy else 503, {« Cache-Control »: « no-store »}

Ajoutez une vérification Redis de la même façon si vous l’utilisez pour les sessions ou une file de tâches.

Testez le cas d’échec

Un health check qui n’a jamais échoué n’a jamais été testé. En préproduction, arrêtez la base de données ou pointez l’application vers un mauvais hôte de cache, et confirmez que l’endpoint renvoie 503 dans votre délai et nomme la bonne vérification. Confirmez ensuite que la réponse ne contient aucun texte d’erreur. Cela prend dix minutes et vous garantit que l’endpoint dira la vérité quand ce sera important.

Surveiller l’endpoint

Un endpoint que personne ne contrôle depuis l’extérieur, c’est la moitié du travail. Pointez dessus un moniteur HTTP situé hors de votre réseau, pour qu’il détecte aussi les problèmes de DNS, de TLS, de pare-feu et de load balancer :

Surveillez https://lumenanalytics.io/health en GET toutes les minutes.

Attendez le statut 200 et vérifiez que le corps contient « status »: »ok ». Une page d’erreur de proxy qui renverrait 200 fait alors quand même échouer le contrôle.

Envoyez un en-tête user agent personnalisé, pour filtrer facilement le trafic de surveillance dans vos statistiques et vos logs.

Suivez l’historique des temps de réponse. Un health check qui passe peu à peu de 40 ms à 900 ms annonce une base de données en difficulté.

Envoyez l’alerte aux personnes responsables du service.

La surveillance d’API d’Uptimecheck prend en charge les méthodes et en-têtes personnalisés (y compris l’authentification basic ou un bearer token) et valide le statut attendu, les mots-clés et les champs JSON : cette configuration prend donc une minute. Gardez à côté un moniteur de disponibilité classique sur la page d’accueil et sur la page de conversion la plus importante ; la checklist de surveillance d’API couvre les autres endpoints à surveiller.

Les workers de file d’attente et les tâches planifiées tournent souvent en dehors du processus web : un endpoint de santé ne peut donc pas voir s’ils se sont arrêtés. Donnez-leur plutôt des heartbeats : le worker appelle une URL toutes les quelques minutes, et un ping manquant déclenche l’alerte.

Checklist de l’endpoint de health check

Séparez la liveness (processus vivant) de la readiness (dépendances fonctionnelles).

Vérifiez la base de données, le cache, le disque et la file d’attente dont l’application a besoin pour servir une requête.

Donnez à chaque vérification un délai court et gardez des requêtes triviales.

Renvoyez 200 quand tout va bien et 503 quand une vérification obligatoire échoue.

Ne renvoyez que les noms et états des vérifications. Pas d’erreurs, de versions ni de noms d’hôtes.

Désactivez la mise en cache pour ce chemin.

Surveillez-le toutes les minutes depuis l’extérieur, avec validation de la réponse.

Uptimecheck surveille les endpoints de santé, les API, les serveurs et les tâches planifiées dans un seul compte. Démarrez un essai gratuit de 14 jours, sans carte bancaire.

Questions

Que doit renvoyer un endpoint de health check ?

Un petit corps JSON avec un statut global et l’état de chaque vérification, accompagné de HTTP 200 quand tout ce qui est obligatoire fonctionne et de HTTP 503 quand une vérification obligatoire échoue.

Un health check doit-il tester la base de données ?

Le contrôle de readiness, oui, avec une requête triviale comme SELECT 1 et un délai court. Le contrôle de liveness, non : une panne de la base de données redémarrerait alors toutes les instances de l’application.

Peut-on rendre un endpoint de santé public sans risque ?

Oui, s’il ne renvoie que les noms et états des vérifications. Gardez les messages d’erreur, les versions, les noms d’hôtes et les détails de connexion hors de la réponse, et consignez-les plutôt dans les logs du serveur.

À quelle fréquence surveiller un endpoint de health check ?

Toutes les minutes pour les services en production. Vérifiez que le corps contient le statut attendu en plus du code de statut, pour qu’une page en cache ou une page d’erreur de proxy ne passe pas.

À lire aussi

Guides 7 min de lecture

Comment réduire les fausses alertes de la surveillance de disponibilité

Les fausses alertes apprennent aux équipes à ignorer la surveillance. Comment réduire le bruit : confirmer chaque panne par une seconde vérification, fixer des délais d’expiration raisonnables, valider la bonne URL et envoyer les alertes aux personnes qui peuvent agir.

Lire

Guides 5 min de lecture

Checklist de surveillance d’API : au-delà du 200 OK

Une API peut renvoyer 200 et pourtant être cassée. Une checklist pratique pour la surveillance d’API : méthodes, en-têtes, corps de requête, authentification, réponses attendues et seuils de temps de réponse.

Lire

Guides 4 min de lecture

Le coût d’une panne de site web : comment calculer le vôtre

Que coûte vraiment une heure hors ligne ? Une formule simple pour les coûts directs et cachés de l’indisponibilité, des exemples chiffrés et ce que les pourcentages de disponibilité représentent en argent.

Lire

Les pannes, c’est du passé.

Configurez votre premier moniteur en moins d’une minute, ou explorez d’abord la démo en ligne.

Essai gratuit de 14 jours · Puis gratuit pour 5 moniteurs · Sans carte bancaire