Retry Policy — təkrar sorğu siyasəti — mobil tətbiqin uğursuz şəbəkə çağırışlarını nə vaxt və necə avtomatik təkrarlayacağını müəyyən edən qaydalar toplusu. Qeyri-sabit əlaqə və ya müvəqqəti server xətaları zamanı düzgün təkrar siyasəti istifadəçinin iştirakı olmadan tətbiqin etibarlılığını artırır. Google Developer Relations (2025) araşdırmasına görə, Retry Policy-nin düzgün tətbiqi tez-tez şəbəkə əməliyyatları olan mobil tətbiqlərdə itirilmiş sorğuların faizini 40-60% azaldır.
Əsas məqamlar
Retry Policy — şəbəkə sorğusu uğursuz olduqda müştərinin davranışını müəyyən edən proqram strategiyası: hansı xətaları təkrarlamaq, neçə dəfə, hansı gecikmə ilə və cəhdləri nə vaxt dayandırmaq. Mobil tətbiqlərdə təkrar siyasəti mobil şəbəkələrin qeyri-sabitliyi və server tərəfində mümkün müvəqqəti nasazlıqlar səbəbindən kritik əhəmiyyət kəsb edir.
Əsas Retry Policy üç parametri əhatə edir: maksimum təkrarlama sayı (maxRetries), başlanğıc gecikmə (baseDelay) və gecikmə artım strategiyası (backoff strategy). Əlavə olaraq, təkrarla cavab verilməli HTTP statuslarının siyahısı və bütün cəhdlərin dayandırılması üçün vaxt təyin edilə bilər.
Martin Kleppmannın "Designing Data-Intensive Applications" kitabına görə, paylanmış sistemlərdə nasazlıqların 50%-i müvəqqəti xarakter daşıyır və təkrar cəhd zamanı aradan qaldırılır. Bu, Retry Policy-ni server arxitekturasında dəyişiklik etmədən mobil tətbiqin nasazlığa davamlılığını artırmağın ən təsirli və ucuz üsullarından birinə çevirir.
Müvəqqəti xətalar (retriable) — Retry Policy-nin reaksiya verməli olduğu yeganə nasazlıq növü. Bunlara bağlantı vaxtının aşılması (SocketTimeoutException), serverin müvəqqəti əlçatan olmaması (HTTP 503, 502) və DNS xətaları daxildir. Daimi xətalar — HTTP 400, 401, 403, 404 — təkrarlamağın mənası yoxdur, çünki onlar şəbəkə və ya serverdə deyil, sorğuda problem olduğunu göstərir.
AWS Architecture Blog araşdırmasına görə, xətaların retriable və non-retriable bölünməsi Retry Policy-nin layihələndirilməsində ən vacib qərardır. Idempotent olmayan HTTP 401 sorğusunun təkrarlanması hesabın bloklanmasına, HTTP 400-ün təkrarlanması isə məlumat dublikatlarının yaranmasına səbəb ola bilər. Həmişə təkrarlanacaq kodların siyahısını açıq şəkildə konfiqurasiya edin.
Fixed interval — ən sadə strategiya: hər təkrar eyni vaxt intervalından sonra yerinə yetirilir. Məsələn, 2 saniyə gecikmə ilə tətbiq sorğunu 2, 2, 2 saniyədən sonra təkrarlayır. Fixed interval tətbiqdə sadə və proqnozlaşdırıla biləndir, lakin kütləvi nasazlıqlar zamanı serverə bərabər yük yaradır.
Incremental interval — gecikmə hər təkrarla xətti olaraq artır: birinci təkrar 1 saniyədən sonra, ikinci — 2, üçüncü — 3 və s. Bu strategiya təkrarlanan nasazlıqlar zamanı serverə bərpa olunmaq üçün daha çox vaxt verir, lakin eyni anda uğursuz olan çoxlu müştərilər üçün hələ də proqnozlaşdırıla biləndir.
| Strategiya | Gecikmə düsturu | Kumulativ vaxt (3 cəhd) | Tətbiq |
|---|---|---|---|
| Fixed | delay = D | 3 × D | Sadə ssenarilər, yerli vaxt aşmaları |
| Incremental | delay = N × D | 6 × D | Yükün tədricən azaldılması |
| Exponential | delay = D × 2^N | 7 × D | Kütləvi nasazlıqlar, bulud xidmətləri |
| Exponential + Jitter | delay = random(0, D × 2^N) | dəyişkən | Yüksək yük, mikroxidmətlər |
Strategiyanın seçimi tətbiqin xarakterindən asılıdır. Mobil cihazlarda məlumat sinxronizasiyasının fon tapşırıqları üçün jitter ilə exponential strategiya optimaldır — server və istifadəçi cihazına minimal yüklə ən yüksək uğur ehtimalını verir.
Exponential backoff — gecikmənin hər cəhddə ikiqat artdığı strategiya. Başlanğıc gecikmə 1 saniyədirsə, gecikmə ardıcıllığı 1, 2, 4, 8, 16 saniyə olacaq. Bu, serverə bərpa olunmaq üçün eksponensial artan vaxt verir.
Jitter — çoxlu müştərilərdən sinxron təkrar sorğuların qarşısını alan təsadüfi gecikmə sapması (thundering herd problemi). Jitter olmadan eyni Retry Policy-yə malik minlərlə müştəri eyni anda sorğuları təkrarlayaraq serverdə pik yük yaradacaq. Jitter təkrarları zamanla yayır.
Kotlin korutinləri əsas axını bloklamadan jitter ilə exponential backoff tətbiq etməyə imkan verir. kotlinx-coroutines-dən retry funksiyası təkrar şərtini və sorğu gövdəsi olan bloku qəbul edir, gecikmələri və cəhd sayını avtomatik idarə edir.
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 funksiyası şəbəkə çağırışı ilə lambda qəbul edir və onu exponential backoff və jitter ilə yerinə yetirir. Xəta təkrarlanmaya məruz qalmırsa (retriable deyil) və ya maksimum cəhd sayı aşılıbsa, funksiya xəta qaytarır. Gecikmə təkrarların vahid paylanması üçün 0.5-dən 1.5-ə qədər təsadüfi əmsalla vurulur.
Circuit Breaker — xidmətin uzun müddət əlçatan olmaması halında sonsuz təkrar sorğuların qarşısını alan dizayn nümunəsi. Xətaların sayı həddi aşdıqda, Circuit Breaker OPEN vəziyyətinə keçir və sorğunu yerinə yetirmədən dərhal xəta qaytarır, serverə bərpa olunmaq üçün vaxt verir.
Mobil tətbiqlərdə Circuit Breaker planlı texniki xidmət və ya operator şəbəkəsi nasazlıqları səbəbindən API-nin əlçatan olmaması halında xüsusilə faydalıdır. O olmadan tətbiq batareyanı və trafiki sonsuz təkrar cəhdlərə sərf edərək istifadəçi təcrübəsini pisləşdirir və cihazın batareya ilə iş müddətini qısaldır.
Üç vəziyyət Circuit Breaker: CLOSED (normal iş, sorğular yerinə yetirilir), OPEN (imtina, sorğular bloklanır) və HALF_OPEN (bərpanı yoxlamaq üçün sınaq sorğusu). OPEN vəziyyətində müəyyən vaxtdan sonra keçid HALF_OPEN-ə keçir və bir sorğu yerinə yetirir — uğur olduqda CLOSED-ə qayıdır, uğursuzluqda — 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
}
}
}
Kotlin-də Circuit Breaker tətbiqi xəta sayğacı və bərpa taymerini ehtiva edir. protect metodu bloklanan sorğunu yerinə yetirməzdən əvvəl cari vəziyyəti yoxlayır və nasazlıqlar zamanı xəta sayğacını yeniləyir. failureThreshold həddinə çatdıqda, timeoutMs müddəti bitənə qədər bütün sorğular dərhal rədd edilir.
Mobil şəbəkələr Retry Policy-ni xüsusilə vacib edən xüsusiyyətlərə malikdir. Wi-Fi və mobil məlumat arasında keçid, metropoliten və tunellərdə siqnal itkisi, operator səviyyəsində müvəqqəti bloklamalar — bütün bu ssenarilər təkrar cəhdlərlə uğurla həll olunan sorğu nasazlıqlarına səbəb olur.
Android-də Retrofit kitabxanası və OkHttp Interceptor vasitəsilə daxili RetryPolicy mexanizmini təmin edir. iOS-da məsələ URLSessionConfiguration və xüsusi delegasiya ilə həll olunur. Platformalararası inkişaf üçün Ktor (KMP) konfiqurasiya edilə bilən strategiyalarla daxili retry dəstəyini ehtiva edir.
Combine — Apple-ın reaktiv proqramlaşdırma çərçivəsi. Combine-də retry operatoru xəta zamanı publisher-i müəyyən sayda təkrarlayır, lakin təkrarlar arasında gecikməni konfiqurasiya etməyə imkan vermir. Tam dəyərli Retry Policy üçün gecikmə ilə catch və flatMap-in xüsusi kombinasiyası istifadə olunur.
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-də Publisher üçün retryWithBackoff genişləndirməsi sayğacı azaltmaq və gecikməni ikiqat artırmaqla rekursiv çağırış vasitəsilə exponential backoff tətbiq edir. delay operatoru təkrarlar arasında pauza yaradır, catch isə xətanı tutaraq yenidən cəhd etmək və ya failure qaytarmaq qərarını verir.
Birinci səhv — idempotentliyi yoxlamadan sorğuları təkrarlamaq. Server resurs yaradıbsa, lakin şəbəkə nasazlığı səbəbindən təsdiq qaytarmayıbsa, təkrar sorğu dublikat yaradacaq. POST sorğuları üçün həmişə başlıqda idempotent açar (Idempotency-Key) istifadə edin və ya retry-ni yalnız GET, PUT və DELETE üçün tətbiq edin.
İkinci səhv — sonsuz təkrarlar (retry forever). Həmişə maksimum cəhd sayı təyin edin (mobil tətbiqlər üçün 3-5) və bütün cəhdlər üçün ümumi vaxt limiti qoyun. Sonsuz təkrarlar batareyanı boşaldır və serverə parazit yük yaradır, xüsusən də verilənlər bazası miqrasiyası və ya API dəyişikliyi zamanı.
Üçüncü səhv — tətbiqin kontekstini nəzərə almamaq. İstifadəçi tətbiqi bağladıqda və ya fon rejiminə keçdikdə, aktiv Retry Policy düzgün şəkildə ləğv edilməlidir. Ekran bağlandıqda təkrarların avtomatik ləğvi üçün SupervisorScope ilə korutinlərdən və ya UI həyat dövrü ilə Combine-dən istifadə edin.
Dördüncü səhv — təkrar cəhdləri qeydiyyata almamaq. Qeydiyyat olmadan neçə sorğunun təkrarlandığını, hansı xətaların baş verdiyini və Retry Policy-nizin nə dərəcədə effektiv olduğunu bilməyəcəksiniz. Metrikalar əlavə edin: təkrarların sayı, təkrardan sonra uğur, gecikmə paylanması. Bu məlumatlar strategiyanın optimal parametrlərini konkret tətbiq üçün tənzimləməyə kömək edəcək.
Tez-tez verilən suallar
Optimal təkrarlama sayı — əksər ssenarilər üçün 3-5 cəhd. Fon sinxronizasiyası üçün 5-7 cəhd, interaktiv sorğular üçün (məsələn, formanın göndərilməsi) — 3-dən çox olmamalıdır. Daha çox təkrarlama uğur ehtimalını artırmır, lakin istifadəçinin batareyasını və trafikini sərf edir.
Exponential backoff — təkrar cəhdlər arasında gecikmənin ikiqat artmasıdır: 1 saniyə, 2, 4, 8, 16 və s. Server həddindən artıq yüklənibsə, ilk təkrarlar arasında qısa pauza ona tez cavab verməyə imkan verir, hər növbəti cəhddə artan pauza isə serverə bərpa olunmaq üçün getdikcə daha çox vaxt verir.
Yalnız müvəqqəti xətaları təkrarlayın: 408 (Request Timeout), 429 (Too Many Requests), 502 (Bad Gateway), 503 (Service Unavailable), 504 (Gateway Timeout). 4xx xətaları (408 və 429 istisna olmaqla) müştəri problemlərini göstərir — onları təkrarlamağın mənası yoxdur və istifadəçi məlumatları üçün təhlükəli ola bilər.
Retry Policy nasazlıq zamanı bir sorğunun təkrarlanmasını idarə edir. Circuit Breaker xidmətlə əlaqə vəziyyətini idarə edir: xətalar yığıldıqda dövrəni açır (OPEN) və yeni sorğulara icazə vermir. Retry ayrıca çağırış səviyyəsində, Circuit Breaker isə xidmətlə inteqrasiya səviyyəsində işləyir.
Test üçün Android-də NetworkInterceptor (OkHttp) və iOS-da URLProtocol (URLSession) istifadə edərək şəbəkə nasazlıqlarını simulyasiya edin. Parametrləri təyin edin: xəta tezliyi, əlçatan olmama müddəti və cavab kodları. MockWebServer (OkHttp) və ya OHHTTPStubs (iOS) ilə vahid testlər real şəbəkə olmadan təkrar məntiqini yoxlayır.
Nəticə
Açar təslim mobil tətbiq hazırlayacağıq
IT Sectr 2017-ci ildən startaplar və bizneslər üçün iOS və Android tətbiqləri yaradır. Sizə məsləhət verəcəyik və ən yaxşı həlli təklif edəcəyik.
Həm də oxuyun