Retry Policy dans le développement mobile — essence, stratégies et principes

Auteur : IT Sectr Publié le : 2026-03-11 Temps de lecture : 10 min

La Retry Policy — politique de reprise — est un ensemble de règles qui déterminent quand et comment une application mobile répète automatiquement les appels réseau ayant échoué. Avec des connexions instables ou des erreurs temporaires du serveur, une politique de reprise bien conçue améliore la fiabilité de l'application sans intervention de l'utilisateur. Selon une étude de Google Developer Relations (2025), une implémentation correcte de la Retry Policy réduit le pourcentage de requêtes perdues de 40 à 60 % dans les applications mobiles avec des opérations réseau fréquentes.

Points clés

  • Retry Policy — une stratégie de répétition automatique des requêtes en cas d'échec réseau ou d'erreurs temporaires du serveur.
  • Exponential backoff — une méthode d'augmentation du délai entre les tentatives pour réduire la charge du serveur.
  • Jitter — une déviation aléatoire du délai qui empêche l'effet de troupeau (thundering herd).
  • Idempotence — une exigence clé pour les reprises sûres : une requête répétée ne doit pas provoquer d'effets secondaires.
  • Circuit Breaker — un mécanisme pour arrêter les tentatives lors d'une indisponibilité prolongée du service afin de préserver les ressources.

Qu'est-ce que la Retry Policy ?

Retry Policy — une stratégie logicielle qui définit le comportement du client en cas d'échec d'une requête réseau : quelles erreurs doivent être reprises, combien de fois, avec quel délai et quand arrêter les tentatives. Dans les applications mobiles, la politique de reprise est d'une importance cruciale en raison de l'instabilité des réseaux mobiles et des pannes temporaires possibles du côté serveur.

Une Retry Policy de base comprend trois paramètres : le nombre maximum de tentatives (maxRetries), le délai initial (baseDelay) et la stratégie de backoff. De plus, une liste de codes d'état HTTP qui doivent déclencher une tentative peut être spécifiée, ainsi qu'un délai d'attente pour abandonner toutes les tentatives.

Selon le livre « Designing Data-Intensive Applications » de Martin Kleppmann, 50 % des pannes dans les systèmes distribués sont temporaires et sont résolues par une nouvelle tentative. Cela fait de la Retry Policy l'un des moyens les plus efficaces et les moins coûteux d'améliorer la tolérance aux pannes d'une application mobile sans modifier l'architecture du serveur.

Quelles erreurs doivent être reprises

Les erreurs temporaires (pouvant être reprises) sont le seul type de panne auquel la Retry Policy doit répondre. Cela inclut les délais d'attente de connexion (SocketTimeoutException), l'indisponibilité temporaire du serveur (HTTP 503, 502) et les erreurs DNS. Les erreurs permanentes — HTTP 400, 401, 403, 404 — ne doivent pas être reprises, car elles indiquent un problème dans la requête, non dans le réseau ou le serveur.

Selon l'AWS Architecture Blog, la classification correcte des erreurs en récupérables et non récupérables est la décision la plus importante lors de la conception d'une Retry Policy. Reprendre une requête non idempotente avec HTTP 401 peut entraîner le blocage du compte, et reprendre HTTP 400 peut créer des données en double. Configurez toujours explicitement la liste des codes à reprendre.

Stratégies de base de répétition

Intervalle fixe — la stratégie la plus simple : chaque tentative est effectuée après le même intervalle de temps. Par exemple, avec un délai de 2 secondes, l'application répète la requête après 2, 2, 2 secondes. L'intervalle fixe est simple à implémenter et prévisible, mais crée une charge uniforme sur le serveur en cas de pannes massives.

Intervalle incrémental — le délai augmente linéairement à chaque tentative : première tentative après 1 seconde, deuxième après 2, troisième après 3, et ainsi de suite. Cette stratégie donne au serveur plus de temps pour récupérer en cas de pannes répétées, mais reste prévisible pour de nombreux clients échouant simultanément.

StratégieFormule de délaiTemps cumulé (3 tentatives)Application
Fixedelay = D3 × DScénarios simples, timeouts locaux
Incrémentaldelay = N × D6 × DRéduction progressive de la charge
Exponentieldelay = D × 2^N7 × DPannes massives, services cloud
Exponentiel + Jitterdelay = random(0, D × 2^N)variableCharge élevée, microservices

Le choix de la stratégie dépend de la nature de l'application. Pour les tâches d'arrière-plan de synchronisation de données sur les appareils mobiles, la stratégie exponentielle avec jitter est optimale — elle offre la plus grande probabilité de succès avec une charge minimale sur le serveur et l'appareil de l'utilisateur.

Exponential Backoff et Jitter

L'exponential backoff — une stratégie où le délai entre les tentatives double à chaque essai. Si le délai initial est de 1 seconde, la séquence des délais sera 1, 2, 4, 8, 16 secondes. Cela donne au serveur un temps de récupération qui croît de façon exponentielle.

Le Jitter — une déviation aléatoire du délai qui empêche les requêtes de reprise synchrones de plusieurs clients (problème du thundering herd). Sans jitter, mille clients avec la même Retry Policy répéteraient les requêtes simultanément, créant une charge de pointe sur le serveur. Le jitter disperse les tentatives dans le temps.

Implémentation en Kotlin avec les coroutines

Les coroutines Kotlin permettent d'implémenter l'exponential backoff avec jitter sans bloquer le thread principal. La fonction retry de kotlinx-coroutines prend une condition de reprise et un bloc avec le corps de la requête, gérant automatiquement les délais et le nombre de tentatives.

kotlin
suspend fun RetryPolicy.executeWithRetry(
    block: suspend () -> Result<T>
): Result<T> {
    var lastError: Throwable? = null
    repeat(maxRetries + 1) { attempt ->
        try {
            return block()
        } catch (e: Exception) {
            if (!isRetriable(e) || attempt == maxRetries) {
                return Result.failure(e)
            }
            val delay = (baseDelayMs * (1 shl attempt))
                .toLong()
            val jitteredDelay = (delay * (0.5 + Random.nextDouble())).toLong()
            delay(jitteredDelay)
            lastError = e
        }
    }
    return Result.failure(lastError!!)
}

La fonction executeWithRetry prend un lambda avec un appel réseau et l'exécute avec exponential backoff et jitter. Si l'erreur n'est pas récupérable ou si le nombre maximum de tentatives est dépassé, la fonction retourne une erreur. Le délai est multiplié par un facteur aléatoire de 0,5 à 1,5 pour une distribution uniforme des tentatives.

Circuit Breaker et arrêt des tentatives

Circuit Breaker — un modèle de conception qui empêche les requêtes de reprise infinies lors d'une indisponibilité prolongée du service. Lorsque le nombre d'erreurs dépasse un seuil, le Circuit Breaker passe à l'état OPEN et retourne immédiatement une erreur sans exécuter la requête, donnant au serveur le temps de récupérer.

Dans les applications mobiles, le Circuit Breaker est particulièrement utile lorsqu'une API est indisponible en raison d'une maintenance planifiée ou de pannes réseau de l'opérateur. Sans lui, l'application consommerait batterie et trafic dans des tentatives de reprise infinies, dégradant l'expérience utilisateur et réduisant l'autonomie de l'appareil.

Diagramme d'états du Circuit Breaker

Le Circuit Breaker a trois états : CLOSED (fonctionnement normal, les requêtes sont exécutées), OPEN (panne, les requêtes sont bloquées) et HALF_OPEN (requête de test pour vérifier la récupération). Après un délai d'attente spécifié dans l'état OPEN, le disjoncteur passe à HALF_OPEN et exécute une requête — en cas de succès, il retourne à CLOSED ; en cas d'échec, à OPEN.

kotlin
class CircuitBreaker(
    private val failureThreshold: Int = 3,
    private val timeoutMs: Long = 30000
) {
    private var state = State.CLOSED
    private var failureCount = 0
    private var lastFailureTime: Long = 0

    suspend fun T.protect(block: suspend () -> T): T {
        checkState()
        return try {
            val result = block()
            onSuccess()
            result
        } catch (e: Exception) {
            onFailure()
            throw e
        }
    }
}

L'implémentation du Circuit Breaker en Kotlin contient un compteur d'erreurs et une minuterie de récupération. La méthode protect vérifie l'état actuel avant d'exécuter la requête encapsulée et met à jour le compteur d'erreurs en cas d'échec. Après avoir atteint le failureThreshold, toutes les requêtes sont immédiatement rejetées jusqu'à l'expiration du timeoutMs.

Retry Policy dans les applications mobiles

Les réseaux mobiles ont des caractéristiques qui rendent la Retry Policy particulièrement importante. Le basculement entre Wi-Fi et données mobiles, la perte de signal dans le métro et les tunnels, les blocages temporaires au niveau de l'opérateur — tous ces scénarios entraînent des échecs de requêtes qui peuvent être traités avec succès par des tentatives.

Sur Android, la bibliothèque Retrofit et OkHttp fournissent un mécanisme de reprise intégré via Interceptor. Sur iOS, la tâche est résolue via URLSessionConfiguration et une délégation personnalisée. Pour le développement multiplateforme, Ktor (KMP) inclut un support de reprise intégré avec des stratégies configurables.

Implémentation sur iOS avec Combine

Combine — le framework d'Apple pour la programmation réactive. L'opérateur retry dans Combine répète le publisher un nombre spécifié de fois en cas d'erreur, mais ne permet pas de configurer le délai entre les tentatives. Pour une Retry Policy complète, une combinaison personnalisée de catch et flatMap avec délai est utilisée.

swift
extension Publisher {
    func retryWithBackoff(
        retries: Int = 3,
        baseDelay: TimeInterval = 1.0
    ) -> AnyPublisher<Output, Failure> {
        return self.catch { error -> AnyPublisher in
            guard retries > 0 else {
                return Fail(error).eraseToAnyPublisher()
            }
            return Just(())
                .delay(for: .seconds(baseDelay), scheduler: DispatchQueue.main)
                .flatMap { self.retryWithBackoff(
                    retries: retries - 1,
                    baseDelay: baseDelay * 2
                ) }
                .eraseToAnyPublisher()
        }
        .eraseToAnyPublisher()
    }
}

L'extension retryWithBackoff pour Publisher dans Combine implémente l'exponential backoff via des appels récursifs avec compteur décroissant et délai doublé. L'opérateur delay crée une pause entre les tentatives, tandis que catch intercepte l'erreur et décide s'il faut réessayer ou retourner un échec.

Erreurs courantes dans la Retry Policy

La première erreur — répéter les requêtes sans vérifier l'idempotence. Si le serveur a créé une ressource mais n'a pas retourné de confirmation en raison d'un échec réseau, une nouvelle tentative créera un doublon. Pour les requêtes POST, utilisez toujours une clé d'idempotence (Idempotency-Key) dans l'en-tête ou limitez les reprises aux requêtes GET, PUT et DELETE uniquement.

La deuxième erreur — répéter indéfiniment. Définissez toujours un nombre maximum de tentatives (3 à 5 pour les applications mobiles) et un délai d'attente total pour toutes les tentatives. Les reprises infinies épuisent la batterie et créent une charge parasite sur le serveur, en particulier lors de migrations de bases de données ou de modifications d'API.

La troisième erreur — ignorer le contexte de l'application. Si l'utilisateur a fermé l'application ou est passé en arrière-plan, les Retry Policies actives doivent être correctement annulées. Utilisez des coroutines avec SupervisorScope ou Combine avec le cycle de vie de l'interface utilisateur pour l'annulation automatique des tentatives lors de la fermeture de l'écran.

La quatrième erreur — ne pas journaliser les tentatives. Sans journalisation, vous ne saurez pas combien de requêtes ont été reprises, quelles erreurs se sont produites et quelle est l'efficacité de votre Retry Policy. Ajoutez des métriques : nombre de tentatives, succès après tentative, distribution des délais. Ces données vous aideront à ajuster les paramètres optimaux de la stratégie pour votre application spécifique.

Questions fréquentes

Combien de fois répéter une requête dans une application mobile ?

Le nombre optimal de tentatives est de 3 à 5 pour la plupart des scénarios. Pour la synchronisation en arrière-plan, 5 à 7 tentatives sont acceptables ; pour les requêtes interactives (comme l'envoi d'un formulaire), pas plus de 3. Un nombre plus élevé de tentatives n'augmente pas la probabilité de succès mais consomme la batterie et le trafic de données de l'utilisateur.

Qu'est-ce que l'exponential backoff en termes simples ?

L'exponential backoff — c'est le doublement du délai entre les tentatives : 1 seconde, 2, 4, 8, 16 et ainsi de suite. Si le serveur est surchargé, la courte pause entre les premières tentatives lui permet de répondre rapidement, tandis que la pause croissante à chaque tentative suivante donne au serveur plus de temps pour récupérer.

Quels codes d'état HTTP faut-il répéter ?

Ne répétez que les erreurs temporaires : 408 (Request Timeout), 429 (Too Many Requests), 502 (Bad Gateway), 503 (Service Unavailable), 504 (Gateway Timeout). Les erreurs 4xx (sauf 408 et 429) indiquent des problèmes côté client — les répéter n'a pas de sens et peut être dangereux pour les données de l'utilisateur.

Quelle est la différence entre Retry Policy et Circuit Breaker ?

Retry Policy gère la reprise d'une seule requête en cas d'échec. Le Circuit Breaker gère l'état de la connexion avec un service : lorsque les erreurs s'accumulent, il ouvre le circuit (OPEN) et bloque les nouvelles requêtes. La reprise fonctionne au niveau de l'appel individuel, le Circuit Breaker au niveau de l'intégration du service.

Comment tester la Retry Policy sur les appareils mobiles ?

Pour tester la Retry Policy, utilisez NetworkInterceptor (OkHttp) sur Android et URLProtocol (URLSession) sur iOS pour simuler les pannes réseau. Définissez les paramètres : fréquence des erreurs, durée d'indisponibilité et codes de réponse. Les tests unitaires avec MockWebServer (OkHttp) ou OHHTTPStubs (iOS) vérifient la logique de reprise sans réseau réel.

Résumé

  • Retry Policy — une stratégie de reprise automatique des requêtes réseau lors de pannes temporaires avec des paramètres configurables de délai et de nombre de tentatives.
  • Exponential backoff avec jitter — la stratégie de base pour les applications mobiles, réduisant la charge du serveur lors de pannes massives et empêchant l'effet thundering herd.
  • Idempotence — une condition obligatoire pour répéter en toute sécurité les requêtes non GET : sans elle, une reprise crée des données en double ou des effets secondaires indésirables.
  • Circuit Breaker complète la Retry Policy en empêchant les reprises infinies lors d'une indisponibilité prolongée du service et en économisant les ressources de l'appareil.
  • Classification des erreurs en récupérables (503, 502, timeout) et non récupérables (400, 401, 403) est cruciale pour le bon fonctionnement de la politique de reprise.
  • Maximum 3 à 5 tentatives dans les scénarios interactifs et jusqu'à 7 pour la synchronisation en arrière-plan est la valeur optimale pour les applications mobiles selon Google Developer Relations.
  • Recommandation — implémentez la Retry Policy avec exponential backoff, Circuit Breaker et journalisation pour toutes les requêtes réseau dans les applications mobiles.

Nous développerons une application mobile clé en main

IT Sectr crée des applications iOS et Android pour les startups et les entreprises depuis 2017. Nous vous conseillerons et vous proposerons la meilleure solution.

Discuter du projet

Lisez aussi