রিট্রাই পলিসি — নিয়মের একটি সেট যা নির্ধারণ করে কখন এবং কীভাবে একটি মোবাইল অ্যাপ্লিকেশন স্বয়ংক্রিয়ভাবে ব্যর্থ নেটওয়ার্ক কলগুলি পুনরায় চেষ্টা করে। অস্থির সংযোগ বা অস্থায়ী সার্ভার ত্রুটির সাথে, একটি ভালভাবে ডিজাইন করা রিট্রাই পলিসি ব্যবহারকারীর হস্তক্ষেপ ছাড়াই অ্যাপ্লিকেশনের নির্ভরযোগ্যতা উন্নত করে। Google Developer Relations (2025) গবেষণা অনুসারে, সঠিক রিট্রাই পলিসি বাস্তবায়ন ঘন ঘন নেটওয়ার্ক অপারেশনযুক্ত মোবাইল অ্যাপ্লিকেশনে হারানো অনুরোধের শতাংশ 40–60% হ্রাস করে।
মূল বিষয়
রিট্রাই পলিসি — একটি সফ্টওয়্যার কৌশল যা নেটওয়ার্ক অনুরোধ ব্যর্থ হলে ক্লায়েন্টের আচরণ নির্ধারণ করে: কোন ত্রুটিগুলি পুনরায় চেষ্টা করা উচিত, কতবার, কী বিলম্বে এবং কখন প্রচেষ্টা বন্ধ করতে হবে। মোবাইল অ্যাপ্লিকেশনে, মোবাইল নেটওয়ার্কের অস্থিরতা এবং সম্ভাব্য অস্থায়ী সার্ভার-সাইড ব্যর্থতার কারণে রিট্রাই পলিসি অত্যন্ত গুরুত্বপূর্ণ।
একটি মৌলিক রিট্রাই পলিসিতে তিনটি প্যারামিটার অন্তর্ভুক্ত: সর্বাধিক সংখ্যা পুনরায় চেষ্টা (maxRetries), প্রাথমিক বিলম্ব (baseDelay), এবং ব্যাকঅফ কৌশল। অতিরিক্তভাবে, HTTP স্ট্যাটাস কোডের একটি তালিকা নির্দিষ্ট করা যেতে পারে যার উপর পুনরায় চেষ্টা করে সাড়া দেওয়া উচিত এবং সমস্ত প্রচেষ্টা বাতিল করার জন্য একটি টাইমআউট।
মার্টিন ক্লেপম্যানের বই “Designing Data-Intensive Applications” অনুসারে, বিতরণকৃত সিস্টেমে 50% ব্যর্থতা অস্থায়ী এবং পুনরায় চেষ্টা করে সমাধান করা যায়। এটি রিট্রাই পলিসিকে সার্ভার আর্কিটেকচারে পরিবর্তন ছাড়াই মোবাইল অ্যাপ্লিকেশনের ত্রুটি সহনশীলতা উন্নত করার সবচেয়ে কার্যকর এবং সস্তা উপায়গুলির মধ্যে একটি করে তোলে।
অস্থায়ী ত্রুটিগুলি (রিট্রিয়েবল) — একমাত্র ধরণের ব্যর্থতা যা রিট্রাই পলিসির প্রতিক্রিয়া জানানো উচিত। এর মধ্যে রয়েছে সংযোগ টাইমআউট (SocketTimeoutException), অস্থায়ী সার্ভার অনুপলব্ধতা (HTTP 503, 502), এবং DNS ত্রুটি। স্থায়ী ত্রুটিগুলি — HTTP 400, 401, 403, 404 — পুনরায় চেষ্টা করা অর্থহীন কারণ তারা নেটওয়ার্ক বা সার্ভারে নয়, বরং অনুরোধে সমস্যা নির্দেশ করে।
AWS Architecture Blog গবেষণা অনুসারে, ত্রুটিগুলিকে রিট্রিয়েবল এবং নন-রিট্রিয়েবলে সঠিকভাবে শ্রেণিবদ্ধ করা রিট্রাই পলিসি ডিজাইনের সময় সবচেয়ে গুরুত্বপূর্ণ সিদ্ধান্ত। HTTP 401-এ একটি নন-আইডেম্পোটেন্ট অনুরোধ পুনরায় চেষ্টা করলে অ্যাকাউন্ট লকআউট হতে পারে এবং HTTP 400 পুনরায় চেষ্টা করলে ডুপ্লিকেট ডেটা তৈরি হতে পারে। সর্বদা পুনরায় চেষ্টার জন্য কোডের তালিকা স্পষ্টভাবে কনফিগার করুন।
ফিক্সড ইন্টারভাল — সবচেয়ে সহজ কৌশল: প্রতিটি পুনরায় চেষ্টা একই সময় ব্যবধানের পরে ঘটে। উদাহরণস্বরূপ, 2 সেকেন্ড বিলম্বে, অ্যাপ্লিকেশনটি 2, 2, 2 সেকেন্ড পরে অনুরোধটি পুনরায় চেষ্টা করে। ফিক্সড ইন্টারভাল বাস্তবায়নে সহজ এবং অনুমানযোগ্য, কিন্তু ব্যাপক ব্যর্থতার সময় সার্ভারে সমান লোড তৈরি করে।
ইনক্রিমেন্টাল ইন্টারভাল — প্রতিটি পুনরায় চেষ্টার সাথে বিলম্ব রৈখিকভাবে বৃদ্ধি পায়: প্রথম পুনরায় চেষ্টা 1 সেকেন্ড পরে, দ্বিতীয়টি 2 পরে, তৃতীয়টি 3 পরে, ইত্যাদি। এই কৌশলটি পুনরাবৃত্ত ব্যর্থতার সময় সার্ভারকে পুনরুদ্ধারের জন্য আরও সময় দেয়, তবে একসাথে ব্যর্থ হওয়া অনেক ক্লায়েন্টের জন্য এখনও অনুমানযোগ্য।
| কৌশল | বিলম্ব সূত্র | সঞ্চিত সময় (3 প্রচেষ্টা) | প্রয়োগ |
|---|---|---|---|
| ফিক্সড | delay = D | 3 × D | সরল পরিস্থিতি, স্থানীয় টাইমআউট |
| ইনক্রিমেন্টাল | delay = N × D | 6 × D | ক্রমিক লোড হ্রাস |
| এক্সপোনেনশিয়াল | delay = D × 2^N | 7 × D | ব্যাপক ব্যর্থতা, ক্লাউড পরিষেবা |
| এক্সপোনেনশিয়াল + জিটার | delay = random(0, D × 2^N) | পরিবর্তনশীল | উচ্চ লোড, মাইক্রোসার্ভিস |
কৌশলের পছন্দ অ্যাপ্লিকেশনের প্রকৃতির উপর নির্ভর করে। মোবাইল ডিভাইসে ডেটা সিঙ্ক্রোনাইজেশনের ব্যাকগ্রাউন্ড কাজের জন্য, জিটার সহ এক্সপোনেনশিয়াল কৌশল সর্বোত্তম — এটি সার্ভার এবং ব্যবহারকারীর ডিভাইসে ন্যূনতম লোড সহ সাফল্যের সর্বোচ্চ সম্ভাবনা প্রদান করে।
এক্সপোনেনশিয়াল ব্যাকঅফ — একটি কৌশল যেখানে প্রতিটি প্রচেষ্টার সাথে পুনরায় চেষ্টার মধ্যে বিলম্ব দ্বিগুণ হয়। যদি প্রাথমিক বিলম্ব 1 সেকেন্ড হয়, তবে বিলম্বের ক্রম হবে 1, 2, 4, 8, 16 সেকেন্ড। এটি সার্ভারকে পুনরুদ্ধারের জন্য দ্রুত বর্ধনশীল সময় দেয়।
জিটার — একটি এলোমেলো বিলম্ব বিচ্যুতি যা একাধিক ক্লায়েন্ট থেকে একযোগে পুনরায় চেষ্টা অনুরোধ প্রতিরোধ করে (থান্ডারিং হার্ড সমস্যা)। জিটার ছাড়া, একই রিট্রাই পলিসি সহ হাজার ক্লায়েন্ট একসাথে অনুরোধ পুনরায় চেষ্টা করবে, সার্ভারে পিক লোড তৈরি করবে। জিটার সময়ের সাথে পুনরায় চেষ্টা ছড়িয়ে দেয়।
Kotlin করুটিন মূল থ্রেড ব্লক না করে জিটার সহ এক্সপোনেনশিয়াল ব্যাকঅফ বাস্তবায়নের অনুমতি দেয়। kotlinx-coroutines-এর retry ফাংশন একটি পুনরায় চেষ্টা শর্ত এবং অনুরোধ বডি সহ একটি ব্লক নেয়, স্বয়ংক্রিয়ভাবে বিলম্ব এবং প্রচেষ্টা সংখ্যা পরিচালনা করে।
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 ফাংশন একটি নেটওয়ার্ক কল সহ একটি ল্যাম্বডা নেয় এবং এটি এক্সপোনেনশিয়াল ব্যাকঅফ এবং জিটার সহ কার্যকর করে। যদি ত্রুটিটি রিট্রিয়েবল না হয় বা সর্বাধিক প্রচেষ্টার সংখ্যা অতিক্রম করা হয়, ফাংশনটি একটি ত্রুটি ফেরত দেয়। পুনরায় চেষ্টার সমান বিতরণের জন্য বিলম্বকে 0.5 থেকে 1.5 এর একটি এলোমেলো গুণক দ্বারা গুণ করা হয়।
সার্কিট ব্রেকার — একটি ডিজাইন প্যাটার্ন যা দীর্ঘায়িত পরিষেবা অনুপলব্ধতার সময় অহেতুক পুনরায় চেষ্টা অনুরোধ প্রতিরোধ করে। যখন ত্রুটির সংখ্যা একটি সীমা অতিক্রম করে, সার্কিট ব্রেকার OPEN অবস্থায় পরিবর্তিত হয় এবং অনুরোধ কার্যকর না করেই তাত্ক্ষণিকভাবে ত্রুটি ফেরত দেয়, সার্ভারকে পুনরুদ্ধারের সময় দেয়।
মোবাইল অ্যাপ্লিকেশনে, সার্কিট ব্রেকার বিশেষভাবে কার্যকর যখন API পরিকল্পিত রক্ষণাবেক্ষণ বা অপারেটর নেটওয়ার্ক ব্যর্থতার কারণে অনুপলব্ধ থাকে। এটি ছাড়া, অ্যাপ্লিকেশন অহেতুক পুনরায় চেষ্টায় ব্যাটারি এবং ট্র্যাফিক খরচ করবে, ব্যবহারকারীর অভিজ্ঞতা নষ্ট করবে এবং ডিভাইসের ব্যাটারি লাইফ কমিয়ে দেবে।
সার্কিট ব্রেকারের তিনটি অবস্থা: CLOSED (সাধারণ অপারেশন, অনুরোধ কার্যকর হয়), OPEN (ব্যর্থতা, অনুরোধ ব্লক করা হয়), এবং HALF_OPEN (পুনরুদ্ধার পরীক্ষার জন্য ট্রায়াল অনুরোধ)। OPEN অবস্থায় নির্দিষ্ট টাইমআউটের পরে, ব্রেকার HALF_OPEN-এ পরিবর্তিত হয় এবং একটি অনুরোধ কার্যকর করে — সাফল্যে CLOSED-এ, ব্যর্থতায় 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-এ সার্কিট ব্রেকার বাস্তবায়নে একটি ত্রুটি কাউন্টার এবং একটি পুনরুদ্ধার টাইমার রয়েছে। protect পদ্ধতি র্যাপ করা অনুরোধ কার্যকর করার আগে বর্তমান অবস্থা পরীক্ষা করে এবং ব্যর্থতায় ত্রুটি কাউন্টার আপডেট করে। failureThreshold এ পৌঁছানোর পরে, timeoutMs শেষ না হওয়া পর্যন্ত সমস্ত অনুরোধ তাত্ক্ষণিকভাবে প্রত্যাখ্যান করা হয়।
মোবাইল নেটওয়ার্কগুলির এমন বৈশিষ্ট্য রয়েছে যা রিট্রাই পলিসিকে বিশেষভাবে গুরুত্বপূর্ণ করে তোলে। Wi-Fi এবং মোবাইল ডেটার মধ্যে স্যুইচিং, মেট্রো এবং টানেলে সিগন্যাল হারানো, অপারেটর স্তরে অস্থায়ী ব্লক — এই সমস্ত পরিস্থিতি অনুরোধ ব্যর্থতার দিকে পরিচালিত করে যা পুনরায় চেষ্টা করে সফলভাবে মোকাবেলা করা যেতে পারে।
Android-এ, Retrofit লাইব্রেরি এবং OkHttp ইন্টারসেপ্টরের মাধ্যমে একটি অন্তর্নির্মিত পুনরায় চেষ্টা প্রক্রিয়া প্রদান করে। iOS-এ, কাজটি URLSessionConfiguration এবং কাস্টম ডেলিগেশনের মাধ্যমে সমাধান করা হয়। ক্রস-প্ল্যাটফর্ম ডেভেলপমেন্টের জন্য, Ktor (KMP) কনফিগারযোগ্য কৌশল সহ অন্তর্নির্মিত পুনরায় চেষ্টা সমর্থন অন্তর্ভুক্ত করে।
Combine — রিঅ্যাকটিভ প্রোগ্রামিংয়ের জন্য Apple-এর ফ্রেমওয়ার্ক। Combine-এ retry অপারেটর ত্রুটিতে নির্দিষ্ট সংখ্যক বার পাবলিশার পুনরাবৃত্তি করে, কিন্তু পুনরায় চেষ্টার মধ্যে বিলম্ব কনফিগার করার অনুমতি দেয় না। সম্পূর্ণ রিট্রাই পলিসির জন্য, বিলম্ব সহ catch এবং flatMap-এর কাস্টম সমন্বয় ব্যবহার করা হয়।
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-এ Publisher-এর জন্য retryWithBackoff এক্সটেনশন হ্রাসপ্রাপ্ত কাউন্টার এবং দ্বিগুণ বিলম্ব সহ পুনরাবৃত্ত কলের মাধ্যমে এক্সপোনেনশিয়াল ব্যাকঅফ বাস্তবায়ন করে। delay অপারেটর পুনরায় চেষ্টার মধ্যে বিরতি তৈরি করে, যখন catch ত্রুটি আটকায় এবং সিদ্ধান্ত নেয় পুনরায় চেষ্টা করবে নাকি ব্যর্থতা ফেরত দেবে।
প্রথম ভুল — আইডেম্পোটেন্সি পরীক্ষা না করে অনুরোধ পুনরায় চেষ্টা করা। যদি সার্ভার একটি সংস্থান তৈরি করে কিন্তু নেটওয়ার্ক ব্যর্থতার কারণে নিশ্চিতকরণ না ফেরত দেয়, একটি পুনরায় চেষ্টা ডুপ্লিকেট তৈরি করবে। POST অনুরোধের জন্য, সর্বদা হেডারে একটি আইডেম্পোটেন্সি কী (Idempotency-Key) ব্যবহার করুন অথবা শুধুমাত্র GET, PUT এবং DELETE-এর জন্য পুনরায় চেষ্টায় স্যুইচ করুন।
দ্বিতীয় ভুল — অহেতুক পুনরায় চেষ্টা। সর্বদা একটি সর্বাধিক প্রচেষ্টা সংখ্যা (মোবাইল অ্যাপ্লিকেশনের জন্য 3–5) এবং সমস্ত প্রচেষ্টার জন্য একটি মোট টাইমআউট সেট করুন। অহেতুক পুনরায় চেষ্টা ব্যাটারি নিষ্কাশন করে এবং সার্ভারে পরজীবী লোড তৈরি করে, বিশেষ করে ডেটাবেস মাইগ্রেশন বা API পরিবর্তনের সময়।
তৃতীয় ভুল — অ্যাপ্লিকেশন প্রসঙ্গ উপেক্ষা করা। যদি ব্যবহারকারী অ্যাপ্লিকেশন বন্ধ করে দেয় বা ব্যাকগ্রাউন্ডে চলে যায়, সক্রিয় রিট্রাই পলিসি সঠিকভাবে বাতিল করা উচিত। স্ক্রিন বন্ধ হলে স্বয়ংক্রিয় পুনরায় চেষ্টা বাতিলের জন্য SupervisorScope সহ করুটিন বা UI জীবনচক্র সহ Combine ব্যবহার করুন।
চতুর্থ ভুল — পুনরায় চেষ্টা প্রচেষ্টা লগ না করা। লগিং ছাড়া, আপনি জানতে পারবেন না কতগুলি অনুরোধ পুনরায় চেষ্টা করা হয়েছে, কী ত্রুটি ঘটেছে এবং আপনার রিট্রাই পলিসি কতটা কার্যকর। মেট্রিক্স যোগ করুন: পুনরায় চেষ্টার সংখ্যা, পুনরায় চেষ্টার পরে সাফল্য, বিলম্ব বিতরণ। এই ডেটা আপনার নির্দিষ্ট অ্যাপ্লিকেশনের জন্য অনুকূল কৌশল প্যারামিটার টিউন করতে সাহায্য করবে।
সচরাচর জিজ্ঞাসিত প্রশ্ন
বেশিরভাগ পরিস্থিতির জন্য পুনরায় চেষ্টার সর্বোত্তম সংখ্যা 3–5 প্রচেষ্টা। ব্যাকগ্রাউন্ড সিঙ্ক্রোনাইজেশনের জন্য, 5–7 প্রচেষ্টা গ্রহণযোগ্য; ইন্টারঅ্যাকটিভ অনুরোধের জন্য (যেমন ফর্ম জমা), 3-এর বেশি নয়। বেশি সংখ্যক পুনরায় চেষ্টা সাফল্যের সম্ভাবনা বাড়ায় না কিন্তু ব্যবহারকারীর ব্যাটারি এবং ডেটা ট্র্যাফিক খরচ করে।
এক্সপোনেনশিয়াল ব্যাকঅফ — পুনরায় চেষ্টার মধ্যে বিলম্ব দ্বিগুণ হওয়া: 1 সেকেন্ড, 2, 4, 8, 16 ইত্যাদি। যদি সার্ভার ওভারলোড হয়, প্রথম পুনরায় চেষ্টার মধ্যে সংক্ষিপ্ত বিরতি এটিকে দ্রুত সাড়া দিতে দেয়, যখন প্রতিটি পরবর্তী পুনরায় চেষ্টার সাথে বাড়তে থাকা বিরতি সার্ভারকে পুনরুদ্ধারের জন্য আরও সময় দেয়।
শুধুমাত্র অস্থায়ী ত্রুটিগুলি পুনরায় চেষ্টা করুন: 408 (Request Timeout), 429 (Too Many Requests), 502 (Bad Gateway), 503 (Service Unavailable), 504 (Gateway Timeout)। ত্রুটিগুলি 4xx (408 এবং 429 ছাড়া) ক্লায়েন্ট সমস্যা নির্দেশ করে — সেগুলি পুনরায় চেষ্টা করা অর্থহীন এবং ব্যবহারকারীর ডেটার জন্য বিপজ্জনক হতে পারে।
রিট্রাই পলিসি ব্যর্থতায় একটি একক অনুরোধের পুনরায় চেষ্টা পরিচালনা করে। সার্কিট ব্রেকার একটি পরিষেবার সাথে সংযোগের অবস্থা পরিচালনা করে: ত্রুটি জমা হলে, এটি সার্কিট খোলে (OPEN) এবং নতুন অনুরোধ ব্লক করে। রিট্রাই পৃথক কল স্তরে কাজ করে, সার্কিট ব্রেকার পরিষেবা ইন্টিগ্রেশন স্তরে কাজ করে।
পরীক্ষার জন্য, নেটওয়ার্ক ব্যর্থতা অনুকরণ করতে Android-এ NetworkInterceptor (OkHttp) এবং iOS-এ URLProtocol (URLSession) ব্যবহার করুন। প্যারামিটার সেট করুন: ত্রুটি ফ্রিকোয়েন্সি, অনুপলব্ধতার সময়কাল এবং প্রতিক্রিয়া কোড। MockWebServer (OkHttp) বা OHHTTPStubs (iOS) সহ ইউনিট পরীক্ষা বাস্তব নেটওয়ার্ক ছাড়াই পুনরায় চেষ্টার যুক্তি পরীক্ষা করে।
সারসংক্ষেপ
আমরা একটি মোবাইল অ্যাপ্লিকেশন টার্নকি তৈরি করব
IT Sectr 2017 সাল থেকে স্টার্টআপ এবং ব্যবসার জন্য iOS এবং Android অ্যাপ্লিকেশন তৈরি করে। আমরা আপনাকে পরামর্শ দেব এবং সেরা সমাধান প্রস্তাব করব।
আরও পড়ুন