Retry Policy — het beleid voor herhaalde verzoeken — een set regels die bepaalt wanneer en hoe een mobiele app automatisch mislukte netwerkaanroepen herhaalt. Bij een onstabiele verbinding of tijdelijke serverfouten verhoogt een goed ontworpen herhalingsbeleid de betrouwbaarheid van de app zonder tussenkomst van de gebruiker. Volgens onderzoek van Google Developer Relations (2025) vermindert een correcte implementatie van Retry Policy het percentage verloren verzoeken met 40-60% in mobiele apps met frequente netwerkoperaties.
Belangrijkste punten
Retry Policy — is een softwarestrategie die het gedrag van de client bepaalt bij een mislukt netwerkverzoek: welke fouten te herhalen, hoe vaak, met welke vertraging en wanneer te stoppen met pogingen. In mobiele apps is het herhalingsbeleid van cruciaal belang vanwege de instabiliteit van mobiele netwerken en mogelijke tijdelijke storingen aan de serverzijde.
De basis Retry Policy omvat drie parameters: het maximale aantal herhalingen (maxRetries), de initiële vertraging (baseDelay) en de strategie voor het verhogen van de vertraging (backoff strategy). Daarnaast kan een lijst van HTTP-statuscodes worden opgegeven waarop met een herhaling moet worden gereageerd, en een time-out voor het afbreken van alle pogingen.
Volgens het boek „Designing Data-Intensive Applications" van Martin Kleppmann is 50% van de storingen in gedistribueerde systemen tijdelijk en worden ze verholpen bij een nieuwe poging. Dit maakt Retry Policy een van de meest effectieve en goedkoopste manieren om de fouttolerantie van een mobiele app te verhogen zonder wijzigingen in de serverarchitectuur.
Tijdelijke fouten (retriable) — het enige type storing waarop Retry Policy moet reageren. Hiertoe behoren time-outs van verbindingen (SocketTimeoutException), tijdelijke onbeschikbaarheid van de server (HTTP 503, 502) en DNS-fouten. Permanente fouten — HTTP 400, 401, 403, 404 — hebben geen zin om te herhalen, omdat ze wijzen op een probleem in het verzoek, niet in het netwerk of de server.
Volgens onderzoek van AWS Architecture Blog is de juiste classificatie van fouten in retriable en non-retriable de belangrijkste beslissing bij het ontwerpen van Retry Policy. Het herhalen van een niet-idempotent verzoek met HTTP 401 kan leiden tot blokkering van het account, en het herhalen van HTTP 400 tot het creëren van gegevensduplicaten. Configureer altijd expliciet de lijst met codes voor herhaling.
Fixed interval — de eenvoudigste strategie: elke herhaling wordt na hetzelfde tijdsinterval uitgevoerd. Bij een vertraging van 2 seconden herhaalt de app het verzoek bijvoorbeeld na 2, 2, 2 seconden. Fixed interval is eenvoudig te implementeren en voorspelbaar, maar creëert een gelijkmatige belasting op de server bij massale storingen.
Incremental interval — de vertraging neemt lineair toe met elke herhaling: de eerste herhaling na 1 seconde, de tweede na 2, de derde na 3, enzovoort. Deze strategie geeft de server meer tijd om te herstellen bij herhaalde storingen, maar blijft voorspelbaar voor veel clients die tegelijkertijd uitvallen.
| Strategie | Vertragingsformule | Cumulatieve tijd (3 pogingen) | Toepassing |
|---|---|---|---|
| Fixed | delay = D | 3 × D | Eenvoudige scenario's, lokale time-outs |
| Incremental | delay = N × D | 6 × D | Geleidelijke vermindering van belasting |
| Exponential | delay = D × 2^N | 7 × D | Massale storingen, clouddiensten |
| Exponential + Jitter | delay = random(0, D × 2^N) | variabel | Hoge belasting, microservices |
De keuze van de strategie hangt af van de aard van de app. Voor achtergrondtaken van gegevenssynchronisatie op mobiele apparaten is de exponential strategie met jitter optimaal — deze geeft de hoogste succeskans met minimale belasting van de server en het apparaat van de gebruiker.
Exponential backoff — de strategie waarbij de vertraging tussen herhalingen met elke poging verdubbelt. Als de initiële vertraging 1 seconde is, wordt de reeks vertragingen 1, 2, 4, 8, 16 seconden. Dit geeft de server exponentieel toenemende tijd om te herstellen.
Jitter — willekeurige afwijking van de vertraging die synchrone herhaalde verzoeken van meerdere clients voorkomt (thundering herd-probleem). Zonder jitter zullen duizend clients met dezelfde Retry Policy tegelijkertijd verzoeken herhalen, waardoor een piekbelasting op de server ontstaat. Jitter spreidt de herhalingen in de tijd.
Coroutines in Kotlin maken het mogelijk om exponential backoff met jitter te implementeren zonder de hoofdthread te blokkeren. De functie retry uit kotlinx-coroutines accepteert een herhalingsconditie en een blok met de verzoekbody, en beheert automatisch de vertragingen en het aantal pogingen.
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!!)
}
De functie executeWithRetry accepteert een lambda met een netwerkaanroep en voert deze uit met exponential backoff en jitter. Als de fout niet kan worden herhaald (niet retriable) of het maximale aantal pogingen is overschreden, retourneert de functie de fout. De vertraging wordt vermenigvuldigd met een willekeurige factor van 0,5 tot 1,5 voor een gelijkmatige spreiding van herhalingen.
Circuit Breaker — een ontwerppatroon dat oneindige herhaalde verzoeken voorkomt bij langdurige onbeschikbaarheid van de dienst. Wanneer het aantal fouten de drempel overschrijdt, gaat Circuit Breaker naar de OPEN-status en retourneert onmiddellijk een fout zonder het verzoek uit te voeren, waardoor de server tijd krijgt om te herstellen.
In mobiele apps is Circuit Breaker vooral nuttig bij onbeschikbaarheid van de API vanwege gepland onderhoud of netwerkstoringen van de operator. Zonder dit zal de app batterij en verkeer verbruiken voor oneindige herhaalde pogingen, wat de gebruikerservaring verslechtert en de batterijduur van het apparaat verkort.
Drie statussen van Circuit Breaker: CLOSED (normale werking, verzoeken worden uitgevoerd), OPEN (weigering, verzoeken worden geblokkeerd) en HALF_OPEN (testverzoek om herstel te controleren). Na een bepaalde time-out in de OPEN-status schakelt de schakelaar naar HALF_OPEN en voert een verzoek uit — bij succes terug naar CLOSED, bij mislukking — naar OPEN.
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
}
}
}
De implementatie van Circuit Breaker in Kotlin bevat een foutenteller en een hersteltimer. De methode protect controleert de huidige status voordat het geblokkeerde verzoek wordt uitgevoerd en werkt de foutenteller bij bij storingen. Na het bereiken van de drempel failureThreshold worden alle verzoeken onmiddellijk afgewezen tot het verstrijken van timeoutMs.
Mobiele netwerken hebben kenmerken die Retry Policy bijzonder belangrijk maken. Schakelen tussen Wi-Fi en mobiele data, signaalverlies in de metro en tunnels, tijdelijke blokkades op operaturniveau — al deze scenario's leiden tot verzoekfouten die succesvol worden afgehandeld door herhaalde pogingen.
Op Android bieden de Retrofit-bibliotheek en OkHttp een ingebouwd RetryPolicy-mechanisme via Interceptor. Op iOS wordt het probleem opgelost via URLSessionConfiguration en aangepaste delegatie. Voor cross-platform ontwikkeling bevat Ktor (KMP) ingebouwde ondersteuning voor retry met configureerbare strategieën.
Combine — het Apple-framework voor reactief programmeren. De operator retry in Combine herhaalt de publisher een bepaald aantal keren bij een fout, maar staat niet toe de vertraging tussen herhalingen te configureren. Voor een volledige Retry Policy wordt een aangepaste combinatie van catch en flatMap met vertraging gebruikt.
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()
}
}
De extensie retryWithBackoff voor Publisher in Combine implementeert exponential backoff via een recursieve aanroep met vermindering van de teller en verdubbeling van de vertraging. De operator delay creëert een pauze tussen herhalingen, en catch onderschept de fout en beslist of opnieuw te proberen of failure te retourneren.
Eerste fout — verzoeken herhalen zonder controle op idempotentie. Als de server een resource heeft aangemaakt maar geen bevestiging heeft teruggestuurd vanwege een netwerkstoring, zal het herhaalde verzoek een duplicaat creëren. Gebruik voor POST-verzoeken altijd een idempotente sleutel (Idempotency-Key) in de header of pas retry alleen toe voor GET, PUT en DELETE.
Tweede fout — oneindige herhalingen (retry forever). Stel altijd een maximaal aantal pogingen in (3-5 voor mobiele apps) en een totale time-out voor alle pogingen. Oneindige herhalingen verbruiken de batterij en creëren parasitaire belasting op de server, vooral bij databasemigratie of API-wijzigingen.
Derde fout — het negeren van de context van de app. Als de gebruiker de app heeft gesloten of naar de achtergrond is gegaan, moeten actieve Retry Policy correct worden geannuleerd. Gebruik coroutines met SupervisorScope of Combine met de UI-levenscyclus voor automatische annulering van herhalingen bij het sluiten van het scherm.
Vierde fout — het niet loggen van herhaalde pogingen. Zonder loggen weet u niet hoeveel verzoeken zijn herhaald, welke fouten zijn opgetreden en hoe effectief uw Retry Policy is. Voeg metrieken toe: aantal herhalingen, succes na herhaling, spreiding van vertragingen. Deze gegevens helpen de optimale strategieparameters voor de specifieke app af te stellen.
Veelgestelde vragen
Het optimale aantal herhalingen — 3-5 pogingen voor de meeste scenario's. Voor achtergrondsynchronisatie zijn 5-7 pogingen toegestaan, voor interactieve verzoeken (bijvoorbeeld het verzenden van een formulier) — niet meer dan 3. Een groter aantal herhalingen verhoogt de succeskans niet, maar verbruikt wel de batterij en het dataverkeer van de gebruiker.
Exponential backoff — het verdubbelen van de vertraging tussen herhaalde pogingen: 1 seconde, 2, 4, 8, 16, enzovoort. Als de server overbelast is, stelt een korte pauze tussen de eerste herhalingen hem in staat snel te antwoorden, en een toenemende pauze bij elke volgende poging geeft de server steeds meer tijd om te herstellen.
Herhaal alleen tijdelijke fouten: 408 (Request Timeout), 429 (Too Many Requests), 502 (Bad Gateway), 503 (Service Unavailable), 504 (Gateway Timeout). 4xx-fouten (behalve 408 en 429) wijzen op clientproblemen — ze herhalen heeft geen zin en kan gevaarlijk zijn voor gebruikersgegevens.
Retry Policy beheert de herhaling van een enkel verzoek bij een fout. Circuit Breaker beheert de status van de verbinding met de dienst: bij ophoping van fouten opent het circuit (OPEN) en laat geen nieuwe verzoeken toe. Retry werkt op het niveau van een individuele aanroep, Circuit Breaker — op het niveau van integratie met de dienst.
Voor het testen van Retry Policy gebruikt u NetworkInterceptor (OkHttp) op Android en URLProtocol (URLSession) op iOS om netwerkstoringen te simuleren. Stel parameters in: foutfrequentie, duur van onbeschikbaarheid en antwoordcodes. Unittests met MockWebServer (OkHttp) of OHHTTPStubs (iOS) controleren de herhalingslogica zonder echt netwerk.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook