Erreur et résilience

Les patterns de résilience en action : circuit breaker, retry, timeout et fallback appliqués à des flux réels entre services.

Pourquoi la résilience fait partie du flux

Dans un système distribué, les pannes ne sont pas des exceptions : elles font partie du fonctionnement normal. Des services qui tombent, des réseaux qui échouent, des bases de données qui saturent. La question n’est pas de savoir si le système va tomber en panne, mais comment il se comporte lorsqu’il tombe en panne.

Les patterns de résilience ne sont pas des concepts théoriques isolés. Ils s’appliquent aux flux réels entre services pour que le système continue de fonctionner de manière dégradée plutôt que de s’effondrer complètement.

Les quatre patterns principaux

Timeout

Il définit un temps d’attente maximal pour une opération. Si aucune réponse n’arrive dans ce délai, la requête est annulée et l’erreur est traitée.

Retry

Il réessaie une opération qui a échoué, en partant du principe que la panne peut être passagère (un pic de charge, une erreur réseau momentanée).

Circuit Breaker

Il détecte lorsqu’un service échoue de façon répétée et cesse de lui envoyer des requêtes pendant un certain temps, lui permettant ainsi de se rétablir.

Fallback

Il fournit une réponse alternative lorsque l’opération principale échoue.

Le timeout en action

sequenceDiagram
    participant BFF as BFF
    participant MS as ms-catalog
    participant DB as Database

    BFF->>MS: GET /products (timeout: 3s)
    MS->>DB: SELECT * FROM products
    Note over DB: La DB está lenta (5s)
    
    BFF--xMS: Timeout después de 3s
    BFF->>BFF: Manejar timeout
    BFF->>BFF: Devolver respuesta de caché o error

Comment configurer les timeouts

Chaque appel entre services doit avoir un timeout explicite. Sans timeout, une requête peut rester suspendue indéfiniment, en consommant des ressources.

Règles pratiques :

  • Le timeout doit être supérieur au temps de réponse normal du service
  • Mais inférieur au temps que l’utilisateur est prêt à attendre
  • Différentes opérations peuvent avoir différents timeouts
OpérationTimeout suggéré
Consultation du catalogue2–3 secondes
Création de commande5 secondes
Paiement externe10–30 secondes
Envoi de notification5 secondes

Que faire en cas de timeout

  1. Enregistrer le timeout dans les logs avec son contexte (service, opération, durée)
  2. Renvoyer une réponse dégradée si possible (données en cache, valeurs par défaut)
  3. Ne pas supposer que l’opération a échoué : elle a peut-être abouti mais la réponse s’est perdue

Le retry en action

sequenceDiagram
    participant BFF as BFF
    participant MS as ms-orders

    BFF->>MS: POST /orders
    MS-->>BFF: 503 Service Unavailable

    Note over BFF: Esperar 1s (intento 2)
    BFF->>MS: POST /orders
    MS-->>BFF: 503 Service Unavailable

    Note over BFF: Esperar 2s (intento 3)
    BFF->>MS: POST /orders
    MS-->>BFF: 201 Created

Stratégies de retry

Retry immédiat : réessayer sans attendre. Utile uniquement pour des erreurs très passagères.

Retry avec backoff fixe : attendre un temps fixe entre les tentatives (1s, 1s, 1s).

Retry avec backoff exponentiel : doubler le temps d’attente à chaque tentative (1s, 2s, 4s, 8s). C’est la stratégie la plus recommandée car elle réduit la pression sur le service qui est en train de tomber en panne.

Retry avec jitter : ajouter une composante aléatoire au backoff pour éviter que plusieurs clients ne réessaient au même moment (thundering herd).

Quand réessayer et quand ne pas le faire

Réessayer :

  • Erreurs 503 (Service Unavailable)
  • Erreurs 429 (Too Many Requests)
  • Timeouts réseau
  • Erreurs de connexion

Ne pas réessayer :

  • Erreurs 400 (Bad Request) — la requête est invalide
  • Erreurs 401/403 — problème d’authentification/autorisation
  • Erreurs 404 — la ressource n’existe pas
  • Erreurs 409 (Conflict) — conflit d’état

Idempotence et retry

Si l’on réessaie une opération d’écriture (créer une commande, traiter un paiement), le service récepteur doit être idempotent. Sinon, le retry risque de créer des doublons.

Le circuit breaker en action

stateDiagram-v2
    [*] --> Closed
    Closed --> Open: N fallos consecutivos
    Open --> HalfOpen: Después del timeout
    HalfOpen --> Closed: Request exitoso
    HalfOpen --> Open: Request falla

Les trois états

Closed (fermé) : le circuit fonctionne normalement. Les requêtes passent jusqu’au service. Si les pannes s’accumulent, le circuit s’ouvre.

Open (ouvert) : le circuit est coupé. Les requêtes n’atteignent pas le service ; une erreur ou un fallback est renvoyé immédiatement. Cela protège le service en difficulté et évite que l’appelant ne gaspille des ressources à attendre.

Half-Open (semi-ouvert) : après un certain temps, le circuit laisse passer une requête de test. Si elle réussit, le circuit se ferme. Si elle échoue, il se rouvre.

Exemple concret

Le BFF appelle le microservice de catalogue. Si 5 des 10 dernières requêtes ont échoué :

  1. Le circuit breaker s’ouvre
  2. Pendant 30 secondes, toutes les requêtes vers le catalogue reçoivent un fallback (données en cache)
  3. Après 30 secondes, une requête de test est autorisée
  4. Si elle aboutit, le circuit se ferme et le trafic normal reprend

Configuration typique

ParamètreValeur typique
Seuil de pannes50 % sur une fenêtre de 10 requêtes
Temps à l’état Open30 secondes
Requêtes de test en Half-Open1

Le fallback en action

Lorsqu’une opération échoue (par timeout, circuit breaker ouvert ou erreur), le fallback fournit une alternative :

ServiceFallback
CatalogueRenvoyer les données en cache (même obsolètes)
RecommandationsRenvoyer des produits populaires génériques
Profil utilisateurRenvoyer les données de base du token JWT
NotificationsMettre en file d’attente pour un envoi ultérieur
AnalyticsÉcarter l’événement (non critique)

Niveaux de dégradation

Toutes les pannes n’exigent pas la même réponse. On peut définir des niveaux :

  1. Dégradation minimale : données légèrement obsolètes (cache de 5 minutes)
  2. Dégradation modérée : fonctionnalité réduite (catalogue sans filtres avancés)
  3. Dégradation sévère : fonctionnalité minimale (lecture seule, sans opérations d’écriture)
  4. Indisponibilité : page de maintenance

Combiner les patterns

En pratique, ces patterns se combinent :

BFF → [Timeout: 3s] → [Retry: 3 intentos con backoff] → [Circuit Breaker] → ms-catalog
                                                                    ↓ (si abierto)
                                                              [Fallback: caché]
  1. Le BFF effectue une requête avec un timeout de 3 secondes
  2. En cas de timeout, il réessaie jusqu’à 3 fois avec un backoff exponentiel
  3. Si les tentatives échouent, le circuit breaker s’ouvre
  4. Avec le circuit ouvert, les requêtes suivantes reçoivent directement le fallback

Observabilité de la résilience

Chaque pattern doit générer des métriques et des logs :

  • Timeouts : combien, sur quel service, quelle durée
  • Retries : combien de tentatives, taux de succès à chaque tentative
  • Circuit Breaker : transitions d’état, temps passé dans chaque état
  • Fallbacks : combien de fois activé, quel type de fallback

Ces métriques permettent de détecter les problèmes avant qu’ils ne se transforment en incidents graves.

Résumé

La résilience n’est pas un composant que l’on ajoute à la fin. C’est une propriété du système que l’on conçoit dans chaque flux. Le timeout évite les attentes infinies, le retry gère les pannes passagères, le circuit breaker protège les services saturés et le fallback maintient une fonctionnalité dégradée. Combinés, ils permettent au système de continuer à fonctionner même lorsque certaines de ses parties tombent en panne.