Résilience : disjoncteurs et nouvelles tentatives
Maintenez des systèmes sains malgré les défaillances partielles.
Résilience : disjoncteurs et nouvelles tentatives est une leçon PHP Academy gratuite sur CoddyKit. Ceci est la leçon 4 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage PHP Academy, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours PHP Academy comprend 4 leçons au total.
Schémas de résilience
Dans un système distribué, une défaillance partielle est l'état normal : une dépendance est toujours lente, en cours de redémarrage ou surchargée. La résilience consiste à concevoir chaque service de sorte qu'une dépendance défaillante n'entraîne pas votre service dans sa chute, puis l'ensemble du système.
Cette leçon couvre les principaux outils : délais d'attente, nouvelles tentatives avec temporisation progressive, coupe-circuits, cloisonnements et dégradation progressive — le tout en PHP.
Les délais d'attente en premier
Le réglage de résilience le plus important est le délai d'attente. Sans délai, un service en aval lent maintient vos processus PHP-FPM en attente ; les requêtes s'accumulent ; vous manquez de processus ; votre service tombe en panne parce que quelqu'un d'autre était lent. C'est la défaillance en cascade classique.
Définissez toujours un délai de connexion et un délai total pour chaque requête sortante. Toujours.
<?php
require 'vendor/autoload.php';
use GuzzleHttp\Client;
$http = new Client([
'connect_timeout' => 0.5, // fail fast if we can't even connect
'timeout' => 2.0, // hard cap on the whole call
]);
// A hung dependency now fails in 2s instead of holding a worker forever.Nouvelles tentatives — avec prudence
Les défaillances temporaires (une brève perturbation, une courte coupure réseau, un 503) réussissent souvent lors d'une deuxième tentative. Mais les nouvelles tentatives sont dangereuses : réessayez trop vite et vous amplifiez la charge sur un service qui rencontre déjà des difficultés. Règles à suivre :
- Ne réessayez que les opérations idempotentes et les erreurs réessayables (délais d'attente, 5xx, 429).
- Limitez le nombre de tentatives.
- Ne réessayez jamais les erreurs client 4xx : elles échoueront simplement de nouveau.
Temporisation exponentielle et variation aléatoire
Des nouvelles tentatives à intervalle fixe provenant de nombreux clients se synchronisent et forment un effet de troupeau qui martèle le service en cours de récupération par vagues. La solution consiste à appliquer une temporisation exponentielle (doubler le délai à chaque tentative) ainsi qu'une variation aléatoire pour répartir la charge.
<?php
function backoffDelay(int $attempt, float $base = 0.1, float $cap = 5.0): float {
$exp = min($cap, $base * (2 ** $attempt)); // 0.1, 0.2, 0.4, ...
return mt_rand(0, (int)($exp * 1000)) / 1000; // full jitter: 0..exp
}
for ($i = 0; $i < 5; $i++) {
printf("attempt %d -> wait %.3fs\n", $i, backoffDelay($i));
}Une boucle de nouvelles tentatives
Voici comment combiner les éléments : limiter le nombre de tentatives, réessayer uniquement en cas d'erreurs réessayables, attendre entre les tentatives en appliquant une temporisation avec variation aléatoire, puis signaler la dernière défaillance si toutes les tentatives échouent.
<?php
function withRetry(callable $op, int $maxAttempts = 4): mixed {
$attempt = 0;
while (true) {
try {
return $op();
} catch (\Throwable $e) {
$attempt++;
if ($attempt >= $maxAttempts || !isRetryable($e)) {
throw $e; // give up
}
usleep((int)(backoffDelay($attempt) * 1_000_000));
}
}
}
function isRetryable(\Throwable $e): bool { return $e->getCode() === 0 || $e->getCode() >= 500; }
function backoffDelay(int $a): float { return min(5.0, 0.1 * (2 ** $a)) * (mt_rand(0, 100) / 100); }Le coupe-circuit
Les nouvelles tentatives aident en cas de brèves perturbations, mais si une dépendance est réellement hors service, réessayer chaque requête ne fait que gaspiller du temps et des ressources. Un coupe-circuit suit les défaillances et, lorsqu'elles dépassent un seuil, s'ouvre : il court-circuite les appels et échoue instantanément au lieu d'attendre un service hors service.
Il comporte trois états : Fermé (les appels passent, les défaillances sont comptées), Ouvert (les appels sont rejetés immédiatement) et Semi-ouvert (quelques appels d'essai vérifient la reprise).
Automate d'états du coupe-circuit
Les transitions sont les suivantes : Fermé → Ouvert lorsque les défaillances dépassent le seuil. Ouvert → Semi-ouvert après une période de refroidissement. Semi-ouvert → Fermé après une sonde réussie, ou retour à Ouvert en cas d'échec. L'état doit être partagé entre les processus PHP (Redis/APCu), car chaque requête crée un processus distinct.
<?php
final class CircuitBreaker {
public function __construct(
private int $threshold = 5,
private int $coolDown = 30, // seconds
) {}
public function call(callable $op, array &$state): mixed {
if ($state['status'] === 'open') {
if (time() - $state['openedAt'] < $this->coolDown) {
throw new \RuntimeException('Circuit open - failing fast');
}
$state['status'] = 'half-open'; // time to probe
}
try {
$result = $op();
$state = ['status' => 'closed', 'failures' => 0]; // recovered
return $result;
} catch (\Throwable $e) {
$state['failures'] = ($state['failures'] ?? 0) + 1;
if ($state['failures'] >= $this->threshold || $state['status'] === 'half-open') {
$state['status'] = 'open';
$state['openedAt'] = time();
}
throw $e;
}
}
}Cloisonnements
Inspiré des compartiments d'un navire, le schéma de cloisonnement isole les ressources afin qu'une défaillance dans une zone ne puisse pas faire couler tout le navire. Si tous vos processus peuvent appeler le service Reports lent, une panne de Reports peut mobiliser chaque processus et priver Checkout de ressources.
Répartissez les ressources : groupes de connexions distincts, groupes de processus ou files d'attente distincts pour chaque dépendance, ou limites de concurrence par service en aval — afin qu'une dépendance défaillante n'épuise que sa propre portion.
Dégradation progressive et solutions de repli
Lorsqu'une dépendance non critique est indisponible, dégradez le service au lieu de renvoyer une erreur. Servez une valeur mise en cache, une valeur par défaut ou une expérience réduite. L'état ouvert du coupe-circuit est le déclencheur naturel du chemin de repli.
<?php
function getRecommendations(callable $remoteCall, Redis $cache, string $userId): array {
try {
$recs = $remoteCall($userId);
$cache->setex("recs:$userId", 3600, json_encode($recs));
return $recs;
} catch (\Throwable $e) {
// Fallback 1: last-known-good from cache
if ($cached = $cache->get("recs:$userId")) {
return json_decode($cached, true);
}
// Fallback 2: generic popular items - never block the page
return ['popular-1', 'popular-2'];
}
}Clés d'idempotence pour des nouvelles tentatives sûres
Les nouvelles tentatives ne sont sûres que pour les opérations idempotentes. Pour une action non idempotente comme « débiter une carte », joignez une clé d'idempotence que le serveur utilise pour dédupliquer : si une nouvelle tentative arrive après que la première a déjà réussi (mais que la réponse a été perdue), le serveur renvoie le résultat d'origine au lieu de débiter deux fois.
<?php
function chargeWithRetry(callable $http, string $orderId, int $cents): array {
// Same key across all retries of THIS logical charge
$key = 'charge-' . $orderId;
return withRetry(fn() => $http('POST', '/charges', [
'headers' => ['Idempotency-Key' => $key],
'json' => ['order' => $orderId, 'amount' => $cents],
]));
}
function withRetry(callable $op) { return $op(); } // see earlier sceneTout assembler
Les schémas se composent, et l'ordre compte. Un appel sortant robuste est généralement imbriqué ainsi :
- Délai d'attente sur chaque tentative individuelle (au niveau le plus interne).
- Nouvelles tentatives avec temporisation progressive autour de l'appel soumis au délai d'attente, pour les défaillances temporaires.
- Coupe-circuit autour des nouvelles tentatives, afin qu'une panne prolongée déclenche rapidement le mécanisme.
- Cloisonnement limitant la capacité que cette dépendance peut consommer.
- Solution de repli au niveau le plus externe, pour intercepter tout ce qui remonte.
Des enveloppes de type Resilience4PHP existent, mais comprendre cet empilement est plus important que tout paquet particulier.
Vérification rapide
Choisir le bon schéma.
Récapitulatif
Surmonter une défaillance partielle :
- Les délais d'attente sur chaque appel évitent l'épuisement des processus et les défaillances en cascade.
- Les nouvelles tentatives concernent uniquement les opérations idempotentes et les erreurs réessayables, avec une temporisation exponentielle et une variation aléatoire.
- Les coupe-circuits échouent rapidement (Fermé → Ouvert → Semi-ouvert) lorsqu'une dépendance est hors service.
- Les cloisonnements isolent les ressources afin qu'une défaillance ne puisse pas priver tous les services de ressources.
- La dégradation progressive et les solutions de repli maintiennent les flux essentiels actifs.
Ensemble, ces mécanismes transforment des défaillances inévitables en événements circonscrits et récupérables.
Apprends PHP avec un tuteur IA — gratuit
Écris et exécute du vrai code dans ton navigateur, obtiens de l'aide instantanée d'un tuteur IA disponible 24h/24, et reprends là où tu t'es arrêté sur le web ou dans l'app.
- Cours
- 49
- Leçons
- 195
Questions Fréquemment Posées
La leçon « Résilience : disjoncteurs et nouvelles tentatives » est-elle gratuite ?
Oui — le texte complet de « Résilience : disjoncteurs et nouvelles tentatives » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours PHP Academy, passe à CoddyKit PRO. Le cours PHP Academy comprend 4 leçons au total.
Qu'est-ce que j'apprendrai dans « Résilience : disjoncteurs et nouvelles tentatives » ?
Maintenez des systèmes sains malgré les défaillances partielles. Tu pratiques PHP Academy avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.
Dois-je avoir de l'expérience pour commencer PHP Academy ?
Aucune expérience préalable n'est requise. PHP Academy sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 4 sur 4.
Combien de temps prend la leçon « Résilience : disjoncteurs et nouvelles tentatives » ?
La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.
Peux-tu écrire et exécuter du code dans cette leçon PHP Academy ?
Oui. Chaque leçon PHP Academy inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.
Toutes les leçons de ce cours
- Du monolithe aux microservices
- Communication entre services : REST et gRPC
- Passerelles d’API et découverte de services
- Résilience : disjoncteurs et nouvelles tentatives