Retry Policy — patakaran ng paulit-ulit na mga kahilingan — isang hanay ng mga patakaran na tumutukoy kung kailan at paano awtomatikong inuulit ng mobile app ang mga nabigong tawag sa network. Sa hindi matatag na koneksyon o pansamantalang mga error ng server, ang tamang patakaran ng pag-uulit ay nagpapataas ng pagiging maaasahan ng app nang walang partisipasyon ng gumagamit. Ayon sa pananaliksik ng Google Developer Relations (2025), ang tamang implementasyon ng Retry Policy ay nagbabawas ng porsyento ng mga nawalang kahilingan ng 40-60% sa mga mobile app na may madalas na operasyon sa network.
Mga pangunahing punto
Retry Policy — ay isang estratehiya ng software na tumutukoy sa pag-uugali ng client sa pagkabigo ng isang network request: aling mga error ang uulitin, ilang beses, sa anong pagkaantala, at kailan ititigil ang mga pagtatangka. Sa mga mobile app, ang patakaran ng pag-uulit ay kritikal na mahalaga dahil sa kawalan ng katatagan ng mga mobile network at posibleng pansamantalang pagkabigo sa panig ng server.
Ang pangunahing Retry Policy ay may kasamang tatlong parameter: pinakamataas na bilang ng pag-uulit (maxRetries), paunang pagkaantala (baseDelay), at estratehiya ng pagtaas ng pagkaantala (backoff strategy). Karagdagan, maaaring tukuyin ang isang listahan ng mga HTTP status code na dapat tugunan ng pag-uulit, at isang timeout para sa pag-abort ng lahat ng pagtatangka.
Ayon sa aklat na “Designing Data-Intensive Applications” ni Martin Kleppmann, 50% ng mga pagkabigo sa distributed system ay pansamantala at naaayos sa isang paulit-ulit na pagtatangka. Ginagawa nitong Retry Policy ang isa sa pinaka-epektibo at pinakamurang paraan upang mapataas ang fault tolerance ng isang mobile app nang walang pagbabago sa arkitektura ng server.
Pansamantalang error (retriable) — ang tanging uri ng pagkabigo na dapat tugunan ng Retry Policy. Kabilang dito ang mga timeout ng koneksyon (SocketTimeoutException), pansamantalang hindi pagiging available ng server (HTTP 503, 502), at mga error sa DNS. Ang permanenteng error — HTTP 400, 401, 403, 404 — walang saysay na ulitin, dahil ipinapahiwatig nila ang problema sa kahilingan, hindi sa network o server.
Ayon sa pananaliksik ng AWS Architecture Blog, ang tamang pag-uuri ng mga error sa retriable at non-retriable ang pinakamahalagang desisyon sa pagdidisenyo ng Retry Policy. Ang pag-uulit ng isang non-idempotent na kahilingan na may HTTP 401 ay maaaring humantong sa pag-block ng account, at ang pag-uulit ng HTTP 400 sa paglikha ng mga duplicate ng data. Palaging i-configure ang listahan ng mga code para sa pag-uulit nang tahasan.
Fixed interval — ang pinakasimpleng estratehiya: bawat pag-uulit ay isinasagawa pagkatapos ng parehong agwat ng oras. Halimbawa, sa pagkaantala ng 2 segundo, inuulit ng app ang kahilingan pagkatapos ng 2, 2, 2 segundo. Ang Fixed interval ay simple sa implementasyon at predictable, ngunit lumilikha ng pantay na karga sa server sa mga mass failure.
Incremental interval — ang pagkaantala ay tumataas nang linear sa bawat pag-uulit: unang pag-uulit pagkatapos ng 1 segundo, pangalawa pagkatapos ng 2, pangatlo pagkatapos ng 3, at iba pa. Ang estratehiyang ito ay nagbibigay sa server ng mas maraming oras upang maka-recover sa paulit-ulit na pagkabigo, ngunit predictable pa rin para sa maraming client na sabay-sabay na nabigo.
| Estratehiya | Pormula ng pagkaantala | Pinagsamang oras (3 pagtatangka) | Aplikasyon |
|---|---|---|---|
| Fixed | delay = D | 3 × D | Mga simpleng senaryo, lokal na timeout |
| Incremental | delay = N × D | 6 × D | Unti-unting pagbawas ng karga |
| Exponential | delay = D × 2^N | 7 × D | Mga mass failure, serbisyo sa cloud |
| Exponential + Jitter | delay = random(0, D × 2^N) | variable | Mataas na karga, microservice |
Ang pagpili ng estratehiya ay depende sa katangian ng app. Para sa background na mga gawain ng data synchronization sa mga mobile device, ang exponential na estratehiya na may jitter ay optimal — nagbibigay ito ng pinakamataas na posibilidad ng tagumpay na may minimal na karga sa server at device ng gumagamit.
Exponential backoff — estratehiya kung saan ang pagkaantala sa pagitan ng pag-uulit ay dumodoble sa bawat pagtatangka. Kung ang paunang pagkaantala ay 1 segundo, ang pagkakasunod-sunod ng pagkaantala ay magiging 1, 2, 4, 8, 16 segundo. Ito ay nagbibigay sa server ng exponentially tumataas na oras upang maka-recover.
Jitter — random na paglihis ng pagkaantala na pumipigil sa sabay-sabay na paulit-ulit na kahilingan mula sa maraming client (problema ng thundering herd). Kung walang jitter, libu-libong client na may parehong Retry Policy ay uulit ng mga kahilingan nang sabay-sabay, na lumilikha ng peak load sa server. Ipinapamahagi ng Jitter ang mga pag-uulit sa oras.
Ang mga coroutine ng Kotlin ay nagpapahintulot ng implementasyon ng exponential backoff na may jitter nang hindi binablock ang pangunahing thread. Ang function na retry mula sa kotlinx-coroutines ay tumatanggap ng kondisyon ng pag-uulit at block na may body ng kahilingan, awtomatikong namamahala ng mga pagkaantala at bilang ng mga pagtatangka.
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!!)
}
Ang function na executeWithRetry ay tumatanggap ng lambda na may tawag sa network at isinasagawa ito nang may exponential backoff at jitter. Kung ang error ay hindi pwedeng ulitin (non-retriable) o lumampas na sa maximum na bilang ng pagtatangka, ibinabalik ng function ang error. Ang pagkaantala ay minumultiply sa random na koepisyent mula 0.5 hanggang 1.5 para sa pantay na distribusyon ng pag-uulit.
Circuit Breaker — pattern ng disenyo na pumipigil sa walang katapusang paulit-ulit na kahilingan sa matagal na hindi pagiging available ng serbisyo. Kapag lumampas na ang bilang ng mga error sa threshold, lumipat ang Circuit Breaker sa estado na OPEN at agad na ibinabalik ang error nang hindi isinasagawa ang kahilingan, na nagbibigay sa server ng oras upang maka-recover.
Sa mga mobile app, ang Circuit Breaker ay lalong kapaki-pakinabang sa hindi pagiging available ng API dahil sa naka-iskedyul na maintenance o network failure ng operator. Kung wala ito, gagamitin ng app ang baterya at trapiko sa walang katapusang paulit-ulit na pagtatangka, na nagpapalala sa karanasan ng gumagamit at nagbabawas ng buhay ng baterya ng device.
Tatlong estado ng Circuit Breaker: CLOSED (normal na operasyon, isinasagawa ang mga kahilingan), OPEN (pagtanggi, binblock ang mga kahilingan), at HALF_OPEN (test request para suriin ang pag-recover). Pagkatapos ng tinukoy na timeout sa estado na OPEN, lumipat ang switch sa HALF_OPEN at nagsasagawa ng isang kahilingan — sa tagumpay bumalik sa CLOSED, sa pagkabigo — sa 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
}
}
}
Ang implementasyon ng Circuit Breaker sa Kotlin ay naglalaman ng counter ng error at timer ng pag-recover. Sinusuri ng method na protect ang kasalukuyang estado bago isagawa ang naka-block na kahilingan at ina-update ang counter ng error sa mga pagkabigo. Pagkatapong maabos ang threshold na failureThreshold, lahat ng kahilingan ay agad na tinatanggihan hanggang sa mag-expire ang timeoutMs.
Mga mobile network ay may mga katangian na nagpapahalaga sa Retry Policy. Ang paglipat sa pagitan ng Wi-Fi at mobile data, pagkawala ng signal sa metro at tunnels, pansamantalang pag-block sa level ng operator — lahat ng senaryo na ito ay humahantong sa mga pagkabigo ng kahilingan na matagumpay na pinangangasiwaan ng paulit-ulit na pagtatangka.
Sa Android, ang library na Retrofit at OkHttp ay nagbibigay ng built-in na mekanismo ng RetryPolicy sa pamamagitan ng Interceptor. Sa iOS, ang problema ay nalulutas sa pamamagitan ng URLSessionConfiguration at custom na delegasyon. Para sa cross-platform development, ang Ktor (KMP) ay naglalaman ng built-in na suporta para sa retry na may mga configurable na estratehiya.
Combine — framework ng Apple para sa reactive programming. Ang operator na retry sa Combine ay inuulit ang publisher ng tinukoy na bilang ng beses sa error, ngunit hindi pinapayagan ang configuration ng pagkaantala sa pagitan ng pag-uulit. Para sa buong Retry Policy, ginagamit ang custom na kombinasyon ng catch at flatMap na may pagkaantala.
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()
}
}
Ang extension na retryWithBackoff para sa Publisher sa Combine ay nag-iimplementa ng exponential backoff sa pamamagitan ng recursive na tawag na may pagbawas ng counter at pagdodoble ng pagkaantala. Ang operator na delay ay lumilikha ng pause sa pagitan ng pag-uulit, at ang catch ay sumasalo ng error at nagdedesisyon kung susubok muli o magbabalik ng failure.
Unang pagkakamali — pag-uulit ng mga kahilingan nang hindi sinusuri ang idempotency. Kung ang server ay lumikha ng resource ngunit hindi nagbalik ng kumpirmasyon dahil sa network failure, ang paulit-ulit na kahilingan ay lilikha ng duplicate. Para sa POST requests, palaging gumamit ng idempotent na key (Idempotency-Key) sa header o lumipat sa retry para lamang sa GET, PUT, at DELETE.
Pangalawang pagkakamali — walang katapusang pag-uulit (retry forever). Palaging itakda ang maximum na bilang ng pagtatangka (3-5 para sa mobile apps) at kabuuang timeout para sa lahat ng pagtatangka. Ang walang katapusang pag-uulit ay nauubos ang baterya at lumilikha ng parasitic load sa server, lalo na sa database migration o pagbabago ng API.
Pangatlong pagkakamali — pagwawalang-bahala sa konteksto ng app. Kung isinara ng gumagamit ang app o lumipat sa background mode, ang aktibong Retry Policy ay dapat na maayos na kanselahin. Gumamit ng coroutine na may SupervisorScope o Combine na may UI lifecycle para sa awtomatikong pagkansela ng pag-uulit sa pagsasara ng screen.
Pang-apat na pagkakamali — hindi pag-log ng paulit-ulit na pagtatangka. Kung walang pag-log, hindi mo malalaman kung ilang kahilingan ang naulit, anong mga error ang nangyari, at kung gaano kabisa ang iyong Retry Policy. Magdagdag ng metrics: bilang ng pag-uulit, tagumpay pagkatapos ng pag-uulit, distribusyon ng pagkaantala. Ang data na ito ay makakatulong na i-adjust ang optimal na parameter ng estratehiya para sa partikular na app.
Mga madalas itanong
Ang optimal na bilang ng pag-uulit — 3-5 pagtatangka para sa karamihan ng mga senaryo. Para sa background synchronization, 5-7 pagtatangka ang pinapayagan, para sa mga interactive na kahilingan (halimbawa, pagpapadala ng form) — hindi hihigit sa 3. Ang mas maraming pag-uulit ay hindi nagpapataas ng posibilidad ng tagumpay, ngunit nauubos ang baterya at trapiko ng gumagamit.
Exponential backoff — pagdodoble ng pagkaantala sa pagitan ng paulit-ulit na pagtatangka: 1 segundo, 2, 4, 8, 16, at iba pa. Kung overloaded ang server, ang maikling pause sa pagitan ng unang pag-uulit ay nagpapahintulot dito na mabilis na tumugon, at ang tumataas na pause sa bawat kasunod na pagtatangka ay nagbibigay sa server ng parami nang paraming oras para maka-recover.
Ulitin lamang ang pansamantalang error: 408 (Request Timeout), 429 (Too Many Requests), 502 (Bad Gateway), 503 (Service Unavailable), 504 (Gateway Timeout). Ang mga error na 4xx (maliban sa 408 at 429) ay nagpapahiwatig ng problema sa client — walang saysay na ulitin ang mga ito at maaaring mapanganib para sa data ng gumagamit.
Retry Policy ay namamahala ng pag-uulit ng isang kahilingan sa pagkabigo. Circuit Breaker ay namamahala ng estado ng koneksyon sa serbisyo: sa pag-ipon ng mga error, binubuksan nito ang circuit (OPEN) at hindi pinapayagan ang mga bagong kahilingan. Ang Retry ay gumagana sa antas ng indibidwal na tawag, Circuit Breaker — sa antas ng integrasyon sa serbisyo.
Para sa pag-test ng Retry Policy, gumamit ng NetworkInterceptor (OkHttp) sa Android at URLProtocol (URLSession) sa iOS para i-simulate ang mga network failure. Itakda ang mga parameter: frequency ng error, tagal ng hindi pagiging available, at mga code ng tugon. Ang unit test na may MockWebServer (OkHttp) o OHHTTPStubs (iOS) ay sumusuri ng logic ng pag-uulit nang walang tunay na network.
Buod
Gagawa kami ng mobile application na turnkey
Gumagawa ang IT Sectr ng mga iOS at Android application para sa mga startup at negosyo mula noong 2017. Magpapayo kami sa iyo at magmumungkahi ng pinakamahusay na solusyon.
Basahin din