Yeniden Deneme Politikası — başarısız ağ çağrılarını bir mobil uygulamanın otomatik olarak ne zaman ve nasıl yeniden deneyeceğini belirleyen bir kurallar dizisidir. Kararsız bağlantılar veya geçici sunucu hataları durumunda, iyi tasarlanmış bir yeniden deneme politikası, kullanıcı müdahalesi olmadan uygulamanın güvenilirliğini artırır. Google Developer Relations (2025) araştırmasına göre, Yeniden Deneme Politikasının doğru uygulanması, sık ağ işlemleri olan mobil uygulamalarda kaybedilen isteklerin yüzdesini %40–60 oranında azaltır.
Önemli Noktalar
Yeniden Deneme Politikası — bir ağ isteği başarısız olduğunda istemci davranışını tanımlayan bir yazılım stratejisidir: hangi hatalar yeniden denenmeli, kaç kez, hangi gecikmeyle ve denemeler ne zaman durdurulmalı. Mobil uygulamalarda, mobil ağların kararsızlığı ve olası geçici sunucu tarafı arızaları nedeniyle yeniden deneme politikası kritik öneme sahiptir.
Temel bir Yeniden Deneme Politikası üç parametre içerir: maksimum yeniden deneme sayısı (maxRetries), başlangıç gecikmesi (baseDelay) ve geri çekilme stratejisi. Ek olarak, yeniden denemeyi tetiklemesi gereken HTTP durum kodlarının bir listesi ve tüm denemeleri iptal etmek için bir zaman aşımı belirtilebilir.
Martin Kleppmann'ın “Designing Data-Intensive Applications” kitabına göre, dağıtık sistemlerdeki arızaların %50'si geçicidir ve yeniden denemeyle çözülür. Bu, Yeniden Deneme Politikasını, sunucu mimarisinde değişiklik yapmadan bir mobil uygulamanın hata toleransını iyileştirmenin en etkili ve ucuz yollarından biri haline getirir.
Geçici hatalar (yeniden denenebilir), Yeniden Deneme Politikasının yanıt vermesi gereken tek arıza türüdür. Bunlar arasında bağlantı zaman aşımları (SocketTimeoutException), geçici sunucu kullanılamazlığı (HTTP 503, 502) ve DNS hataları bulunur. Kalıcı hatalar — HTTP 400, 401, 403, 404 — yeniden denenmemelidir çünkü bunlar ağ veya sunucuda değil, istekte bir sorun olduğunu gösterir.
AWS Architecture Blog'a göre, hataları yeniden denenebilir ve yeniden denenemez olarak doğru sınıflandırmak, bir Yeniden Deneme Politikası tasarlarken en önemli karardır. HTTP 401 ile idempotent olmayan bir isteği yeniden denemek hesabın kilitlenmesine yol açabilir ve HTTP 400'ı yeniden denemek yinelenen veriler oluşturabilir. Yeniden denemek için kodların listesini her zaman açıkça yapılandırın.
Sabit aralık — en basit stratejidir: her yeniden deneme aynı zaman aralığından sonra gerçekleşir. Örneğin, 2 saniyelik bir gecikmeyle uygulama, isteği 2, 2, 2 saniye sonra yeniden dener. Sabit aralık uygulaması basit ve öngörülebilirdir, ancak toplu arızalar sırasında sunucuda tek tip yük oluşturur.
Artımlı aralık — gecikme her yeniden denemede doğrusal olarak artar: ilk yeniden deneme 1 saniye sonra, ikincisi 2 saniye sonra, üçüncüsü 3 saniye sonra vb. Bu strateji, tekrarlanan arızalarda sunucuya daha fazla iyileşme süresi verir, ancak aynı anda başarısız olan birçok istemci için hala öngörülebilirdir.
| Strateji | Gecikme Formülü | Kümülatif Süre (3 deneme) | Uygulama |
|---|---|---|---|
| Sabit | delay = D | 3 × D | Basit senaryolar, yerel zaman aşımları |
| Artımlı | delay = N × D | 6 × D | Kademeli yük azaltma |
| Üstel | delay = D × 2^N | 7 × D | Toplu arızalar, bulut hizmetleri |
| Üstel + Jitter | delay = random(0, D × 2^N) | değişken | Yüksek yük, mikro hizmetler |
Strateji seçimi uygulamanın doğasına bağlıdır. Mobil cihazlarda veri senkronizasyonunun arka plan görevleri için, jitter ile üstel strateji idealdir — sunucu ve kullanıcı cihazında minimum yük ile en yüksek başarı olasılığını sağlar.
Üstel geri çekilme — her denemede yeniden denemeler arasındaki gecikmenin ikiye katlandığı bir stratejidir. Başlangıç gecikmesi 1 saniye ise, gecikme sırası 1, 2, 4, 8, 16 saniye olacaktır. Bu, sunucuya katlanarak artan iyileşme süresi verir.
Jitter — birden çok istemciden gelen eşzamanlı yeniden deneme isteklerini (sürü etkisi sorunu) önleyen rastgele bir gecikme sapmasıdır. Jitter olmadan, aynı Yeniden Deneme Politikasına sahip bin istemci istekleri aynı anda yeniden deneyerek sunucuda tepe yükü oluşturur. Jitter, yeniden denemeleri zamana yayar.
Kotlin coroutine'leri, ana iş parçacığını bloke etmeden jitter ile üstel geri çekilme uygulamaya olanak tanır. kotlinx-coroutines'deki retry işlevi, bir yeniden deneme koşulu ve istek gövdesi içeren bir blok alır, gecikmeleri ve deneme sayılarını otomatik olarak yönetir.
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!!)
}
executeWithRetry işlevi, bir ağ çağrısı içeren bir lambda alır ve onu üstel geri çekilme ve jitter ile yürütür. Hata yeniden denenebilir değilse veya maksimum deneme sayısı aşılırsa, işlev bir hata döndürür. Yeniden denemelerin tekdüze dağılımı için gecikme 0,5 ila 1,5 arasında rastgele bir faktörle çarpılır.
Devre Kesici — hizmetin uzun süre kullanılamaması durumunda sonsuz yeniden deneme isteklerini önleyen bir tasarım desenidir. Hata sayısı bir eşiği aştığında, Devre Kesici OPEN durumuna geçer ve isteği yürütmeden hemen bir hata döndürerek sunucuya iyileşme süresi verir.
Mobil uygulamalarda Devre Kesici, planlı bakım veya operatör ağ arızaları nedeniyle bir API kullanılamadığında özellikle kullanışlıdır. Devre Kesici olmadan uygulama, sonsuz yeniden denemelerde pil ve trafik tüketir, kullanıcı deneyimini düşürür ve cihazın pil ömrünü kısaltır.
Devre Kesicinin üç durumu vardır: CLOSED (normal çalışma, istekler yürütülür), OPEN (arıza, istekler engellenir) ve HALF_OPEN (iyileşmeyi kontrol etmek için test isteği). OPEN durumunda belirtilen bir zaman aşımından sonra, kesici HALF_OPEN'e geçer ve bir istek yürütür — başarılı olursa CLOSED'a, başarısız olursa OPEN'a döner.
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
}
}
}
Kotlin'de Devre Kesici uygulaması bir hata sayacı ve bir iyileşme zamanlayıcısı içerir. protect yöntemi, sarılmış isteği yürütmeden önce geçerli durumu kontrol eder ve arızalarda hata sayacını günceller. failureThreshold'a ulaşıldıktan sonra, timeoutMs süresi dolana kadar tüm istekler derhal reddedilir.
Mobil ağlar, Yeniden Deneme Politikasını özellikle önemli kılan özelliklere sahiptir. Wi-Fi ve mobil veri arasında geçiş, metro ve tünellerde sinyal kaybı, operatör düzeyinde geçici engellemeler — tüm bu senaryolar, yeniden denemelerle başarıyla ele alınabilecek istek başarısızlıklarına yol açar.
Android'de Retrofit kütüphanesi ve OkHttp, Interceptor aracılığıyla yerleşik bir yeniden deneme mekanizması sağlar. iOS'ta görev, URLSessionConfiguration ve özel delegasyon ile çözülür. Platformlar arası geliştirme için Ktor (KMP), yapılandırılabilir stratejilerle yerleşik yeniden deneme desteği içerir.
Combine — Apple'ın reaktif programlama çerçevesidir. Combine'daki retry operatörü, hata durumunda publisher'ı belirtilen sayıda tekrarlar, ancak yeniden denemeler arasındaki gecikmeyi yapılandırmaya izin vermez. Tam bir Yeniden Deneme Politikası için, gecikmeli catch ve flatMap 'ın özel bir kombinasyonu kullanılır.
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()
}
}
Combine'daki Publisher için retryWithBackoff uzantısı, azalan sayaç ve iki katına çıkan gecikme ile yinelemeli çağrılar yoluyla üstel geri çekilmeyi uygular. delay operatörü yeniden denemeler arasında bir duraklama oluştururken, catch hatayı yakalar ve yeniden denemeye mi yoksa başarısızlık döndürmeye mi karar verir.
Birinci hata — idempotency kontrolü yapmadan istekleri yeniden denemek. Sunucu bir kaynak oluşturduysa ancak ağ hatası nedeniyle onay döndürmediyse, yeniden deneme bir kopya oluşturacaktır. POST istekleri için, başlıkta her zaman bir idempotency anahtarı (Idempotency-Key) kullanın veya yeniden denemeleri yalnızca GET, PUT ve DELETE ile sınırlayın.
İkinci hata — sonsuz yeniden deneme. Her zaman maksimum deneme sayısı (mobil uygulamalar için 3–5) ve tüm denemeler için toplam bir zaman aşımı belirleyin. Sonsuz yeniden denemeler pili tüketir ve özellikle veritabanı geçişleri veya API değişiklikleri sırasında sunucuda parazit yük oluşturur.
Üçüncü hata — uygulama bağlamını göz ardı etmek. Kullanıcı uygulamayı kapattıysa veya arka plana geçtiyse, aktif Yeniden Deneme Politikaları doğru şekilde iptal edilmelidir. Ekran kapatıldığında otomatik yeniden deneme iptali için SupervisorScope ile coroutine'leri veya UI yaşam döngüsü ile Combine 'ı kullanın.
Dördüncü hata — yeniden denemeleri günlüğe kaydetmemek. Günlükleme olmadan, kaç isteğin yeniden denendiğini, hangi hataların oluştuğunu ve Yeniden Deneme Politikanızın ne kadar etkili olduğunu bilemezsiniz. Metrikler ekleyin: yeniden deneme sayısı, yeniden denemeden sonra başarı, gecikme dağılımı. Bu veriler, belirli uygulamanız için en uygun strateji parametrelerini ayarlamanıza yardımcı olacaktır.
Sık Sorulan Sorular
Çoğu senaryo için en uygun yeniden deneme sayısı 3–5 denemedir. Arka plan senkronizasyonu için 5–7 deneme kabul edilebilir; etkileşimli istekler için (örneğin, form gönderme) en fazla 3. Daha fazla yeniden deneme başarı olasılığını artırmaz ancak kullanıcının pilini ve veri trafiğini tüketir.
Üstel geri çekilme — yeniden denemeler arasındaki gecikmenin ikiye katlanmasıdır: 1 saniye, 2, 4, 8, 16 vb. Sunucu aşırı yüklenmişse, ilk yeniden denemeler arasındaki kısa duraklama sunucunun hızlı yanıt vermesini sağlarken, sonraki her yeniden denemede artan duraklama sunucuya iyileşmesi için daha fazla süre verir.
Yalnızca geçici hataları yeniden deneyin: 408 (Request Timeout), 429 (Too Many Requests), 502 (Bad Gateway), 503 (Service Unavailable), 504 (Gateway Timeout). 4xx hataları (408 ve 429 hariç) istemci sorunlarını gösterir — bunları yeniden denemek anlamsızdır ve kullanıcı verileri için tehlikeli olabilir.
Yeniden Deneme Politikası, bir arıza durumunda tek bir isteğin yeniden denenmesini yönetir. Devre Kesici, bir hizmetle bağlantı durumunu yönetir: hatalar biriktiğinde devreyi açar (OPEN) ve yeni istekleri engeller. Yeniden deneme, bireysel çağrı düzeyinde çalışırken, Devre Kesici hizmet entegrasyonu düzeyinde çalışır.
Test için, ağ arızalarını simüle etmek üzere Android'de NetworkInterceptor (OkHttp) ve iOS'ta URLProtocol (URLSession) kullanın. Parametreleri ayarlayın: hata sıklığı, kullanılamama süresi ve yanıt kodları. MockWebServer (OkHttp) veya OHHTTPStubs (iOS) ile birim testleri, gerçek ağ olmadan yeniden deneme mantığını doğrular.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun