iOS'da URLSession ile zaman aşımı ve yeniden deneme stratejileri, ağ isteklerinin güvenilirliğini artırmak için kullanılır. Timeout değerlerini URLSessionConfiguration ile ayarlayabilir, retry işlemlerini ise özel bir retry handler ile veya üçüncü parti kütüphanelerle gerçekleştirebilirsiniz. Bu sayede kötü ağ koşullarında bile uygulamanız kullanıcıya daha iyi bir deneyim sunar.
URLSession'da Timeout Türleri
URLSession iki temel timeout türü sunar:
- Request Timeout (timeoutIntervalForRequest): İstek gönderildikten sonra yanıt beklenen maksimum süre. Varsayılan değer 60 saniyedir. Düşük ağ koşullarında daha yüksek bir değer (30-60 sn) önerilir.
- Resource Timeout (timeoutIntervalForResource): Tüm isteğin (indirme dahil) tamamlanması için beklenen maksimum süre. Varsayılan 7 gün gibi yüksektir, ancak büyük dosyalar için uygun şekilde ayarlanmalıdır.
Bu değerleri URLSessionConfiguration üzerinden yapılandırabilirsiniz:
let config = URLSessionConfiguration.default
config.timeoutIntervalForRequest = 30
config.timeoutIntervalForResource = 300Retry Stratejileri
Başarısız istekleri otomatik olarak yeniden denemek, kullanıcı deneyimini iyileştirir. Ancak dikkatli uygulanmalıdır:
- Exponential Backoff: Her denemede bekleme süresini katlayarak artırın (1s, 2s, 4s, 8s...). Bu, sunucuya aşırı yük binmesini önler.
- Maksimum Deneme Sayısı: Sonsuz döngüye girmemek için maksimum 3-5 deneme yeterlidir.
- Hata Türüne Göre Retry: Sadece geçici hatalar (zaman aşımı, 503) retry edilmeli. Kalıcı hatalar (401, 404) retry edilmemelidir.
Unutmayın: Sonsuz retry döngüsüne girmemek için maksimum deneme sayısını sınırlayın ve her denemede bekleme süresini artırın (exponential backoff).
Custom Retry Mekanizması Oluşturma
URLSession'da yerleşik retry desteği yoktur. Aşağıdaki adımlarla özel bir retry handler yazabilirsiniz:
- URLSessionDelegate kullanarak hata durumlarını yakalayın.
- Retry kararını verin: Hata kodunu kontrol edin (NSURLErrorTimedOut, NSURLErrorNetworkConnectionLost vb.).
- Bekleme süresini hesaplayın: Exponential backoff formülü ile.
- DispatchQueue kullanarak belirli bir süre sonra isteği tekrarlayın.
Örnek bir retry wrapper şöyle olabilir:
func performRequestWithRetry(_ request: URLRequest, maxRetries: Int = 3, retryDelay: TimeInterval = 1.0, completion: @escaping (Result) -> Void) {
let task = URLSession.shared.dataTask(with: request) { data, response, error in
if let error = error as NSError? {
if shouldRetry(error: error, response: response) && retryCount < maxRetries {
DispatchQueue.main.asyncAfter(deadline: .now() + retryDelay) {
performRequestWithRetry(request, maxRetries: maxRetries - 1, retryDelay: retryDelay * 2, completion: completion)
}
} else {
completion(.failure(error))
}
} else {
completion(.success(data ?? Data()))
}
}
task.resume()
}
func shouldRetry(error: NSError, response: URLResponse?) -> Bool {
let isTimeout = error.code == NSURLErrorTimedOut
let isConnectionLost = error.code == NSURLErrorNetworkConnectionLost
let isServerError = (response as? HTTPURLResponse)?.statusCode == 503
return isTimeout || isConnectionLost || isServerError
}Sık Yapılan Hatalar
- Retry edilmemesi gereken hataları retry etmek: 401, 403 gibi yetkilendirme hataları retry edilmemeli; bunun yerine kullanıcıya oturum açma ekranı gösterilmelidir. Detaylar için Backend API'lerde JWT Token Yönetimi yazısına bakabilirsiniz.
- Çok kısa timeout süreleri: Mobil ağlar yavaş olabilir; 10 saniyenin altındaki request timeout değerleri sık hatalara yol açar.
- UI thread'de retry beklemek: Retry işlemini arka planda yapın, kullanıcı arayüzünü bloke etmeyin.
İleri Seviye: URLProtocol ile Retry
Daha karmaşık senaryolar için özel bir URLProtocol alt sınıfı oluşturabilirsiniz. Bu sayede tüm ağ isteklerinize otomatik olarak retry ve timeout yönetimi ekleyebilirsiniz. Örneğin, Alamofire gibi kütüphaneler bu yaklaşımı kullanır.
Performans ve Kullanıcı Deneyimi İpuçları
- Retry sırasında kullanıcıya progress göstermekten kaçının; arka planda sessizce deneyin.
- Büyük dosya indirmelerinde resource timeout değerini artırın ve background URLSession kullanmayı değerlendirin.
- Timeout ve retry stratejilerinizi farklı ağ koşullarında test edin (WiFi, 3G, zayıf sinyal).
- Android tarafında benzer bir yapı kurmak için Android Retrofit ile REST API Entegrasyonu makalesini inceleyebilirsiniz.
Sonuç
URLSession ile zaman aşımı ve retry stratejilerini doğru uygulamak, mobil uygulamanızın dayanıklılığını ve kullanıcı memnuniyetini artırır. Hata yönetimini unutmayın; REST API Hata Yönetimi yazımızda HTTP durum kodlarını nasıl ele alacağınızı detaylandırdık. Ayrıca, SwiftUI'da MVVM ile State Yönetimi rehberiyle veri akışınızı daha da iyileştirebilirsiniz.
Sık Sorulan Sorular
URLSession'da request timeout vs resource timeout arasındaki fark nedir?
Request timeout, bir isteğin yanıtını beklerken geçen maksimum süreyi belirlerken; resource timeout, tüm isteğin (indirme işlemi dahil) tamamlanması için beklenen toplam süredir. Resource timeout genellikle daha yüksek ayarlanır.
Hangi HTTP hata kodları retry edilmelidir?
Geçici hatalar (zaman aşımı, bağlantı kopması) ve 503 Service Unavailable gibi sunucu hataları retry edilebilir. 401, 403, 404 gibi kalıcı hatalar retry edilmemelidir.
Exponential backoff nedir ve neden kullanılır?
Exponential backoff, her başarısız denemeden sonra bekleme süresini katlayarak artıran bir retry stratejisidir. Bu, sunucuya aşırı yük binmesini önler ve ağ sorunları geçene kadar beklemeyi sağlar.
URLSession'da retry işlemini nasıl test edebilirim?
Test sırasında zayıf ağ koşullarını simüle etmek için Network Link Conditioner aracını kullanabilir veya mock URLSession ile istekleri yönlendirebilirsiniz. Ayrıca, birim testlerinde URLProtocol kullanarak hata döndürebilirsiniz.
Özel retry mekanizması için üçüncü parti kütüphane önerir misiniz?
Alamofire, built-in retry desteği sunar. Ayrıca Moya veya RxSwift gibi reaktif kütüphanelerle de retry kolayca uygulanabilir. Ancak basit projeler için custom wrapper yeterlidir.






