Retry Policy в мобилното разработване — същност, стратегии и принцип

Автор: IT Sectr Публикувано: 2026-03-11 Време за четене: 10 мин

Retry Policy — политика за повторни заявки — набор от правила, определящи кога и как мобилното приложение автоматично повтаря неуспешни мрежови повиквания. При нестабилна връзка или временни грешки на сървъра, добре проектираната политика за повторение повишава надеждността на приложението без участие на потребителя. Според изследване на Google Developer Relations (2025), правилното внедряване на Retry Policy намалява процента на загубени заявки с 40-60% в мобилни приложения с чести мрежови операции.

Основни точки

  • Retry Policy — стратегия за автоматично повторение на заявки при мрежови повреди или временни грешки на сървъра.
  • Exponential backoff — метод за увеличаване на закъснението между повторенията за намаляване на натоварването на сървъра.
  • Jitter — случайно отклонение на закъснението, предотвратяващо ефекта „стадо" (thundering herd).
  • Идемпотентност — ключово изискване за безопасни повторения: повторната заявка не трябва да причинява странични ефекти.
  • Circuit Breaker — механизъм за спиране на повторенията при продължителна недостъпност на услугата за спестяване на ресурси.

Какво е Retry Policy?

Retry Policy — софтуерна стратегия, определяща поведението на клиента при неуспешна мрежова заявка: кои грешки да се повтарят, колко пъти, с какво закъснение и кога да се спрат опитите. В мобилните приложения политиката за повторение е критично важна поради нестабилността на мобилните мрежи и възможни временни повреди от страна на сървъра.

Основната Retry Policy включва три параметъра: максимален брой повторения (maxRetries), начално закъснение (baseDelay) и стратегия за увеличаване на закъснението (backoff strategy). Допълнително може да се зададе списък от HTTP статус кодове, на които да се реагира с повторение, и времево ограничение за прекратяване на всички опити.

Според книгата „Designing Data-Intensive Applications" на Мартин Клепман, 50% от повредите в разпределените системи са временни и се отстраняват при повторен опит. Това прави Retry Policy един от най-ефективните и евтини начини за повишаване на устойчивостта на грешки на мобилно приложение без промени в сървърната архитектура.

Кои грешки си струва да се повтарят

Временни грешки (retriable) — единственият вид повреда, на която Retry Policy трябва да реагира. Те включват таймаути на връзката (SocketTimeoutException), временна недостъпност на сървъра (HTTP 503, 502) и DNS грешки. Постоянни грешки — HTTP 400, 401, 403, 404 — безсмислено е да се повтарят, тъй като показват проблем в заявката, а не в мрежата или сървъра.

Според изследване на AWS Architecture Blog, правилната класификация на грешките на retriable и non-retriable е най-важното решение при проектирането на Retry Policy. Повтарянето на неидемпотентна заявка с HTTP 401 може да доведе до блокиране на акаунт, а повтарянето на HTTP 400 — до създаване на дубликати на данни. Винаги конфигурирайте списъка с кодове за повторение изрично.

Основни стратегии за повторение

Fixed interval — най-простата стратегия: всяко повторение се изпълнява след един и същ интервал от време. Например, при закъснение от 2 секунди, приложението повтаря заявката след 2, 2, 2 секунди. Fixed interval е лесен за внедряване и предвидим, но създава равномерно натоварване на сървъра при масови повреди.

Incremental interval — закъснението се увеличава линейно с всяко повторение: първо повторение след 1 секунда, второ след 2, трето след 3 и така нататък. Тази стратегия дава на сървъра повече време за възстановяване при повтарящи се повреди, но все още е предвидима за много клиенти, които се повреждат едновременно.

СтратегияФормула на закъснениеКумулативно време (3 опита)Приложение
Fixeddelay = D3 × DПрости сценарии, локални таймаути
Incrementaldelay = N × D6 × DПостепенно намаляване на натоварването
Exponentialdelay = D × 2^N7 × DМасови повреди, облачни услуги
Exponential + Jitterdelay = random(0, D × 2^N)променливоВисоко натоварване, микроуслуги

Изборът на стратегия зависи от естеството на приложението. За фонови задачи за синхронизация на данни на мобилни устройства, стратегията exponential с jitter е оптимална — дава най-висока вероятност за успех при минимално натоварване на сървъра и устройството на потребителя.

Exponential Backoff и Jitter

Exponential backoff — стратегия, при която закъснението между повторенията се удвоява с всеки опит. Ако началното закъснение е 1 секунда, последователността на закъсненията ще бъде 1, 2, 4, 8, 16 секунди. Това дава на сървъра експоненциално нарастващо време за възстановяване.

Jitter — случайно отклонение на закъснението, което предотвратява синхронни повторни заявки от множество клиенти (проблемът thundering herd). Без jitter, хиляда клиенти с една и съща Retry Policy ще повтарят заявки едновременно, създавайки пиково натоварване на сървъра. Jitter разпределя повторенията във времето.

Имплементация в Kotlin с корутини

Корутините в Kotlin позволяват имплементиране на exponential backoff с jitter без блокиране на основната нишка. Функцията retry от kotlinx-coroutines приема условие за повторение и блок с тялото на заявката, автоматично управлявайки закъсненията и броя опити.

kotlin
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 приема ламбда с мрежово повикване и я изпълнява с exponential backoff и jitter. Ако грешката не подлежи на повторение (не е retriable) или е превишен максималният брой опити, функцията връща грешка. Закъснението се умножава по случаен коефициент от 0.5 до 1.5 за равномерно разпределение на повторенията.

Circuit Breaker и отказ от повторения

Circuit Breaker — дизайн модел, който предотвратява безкрайни повторни заявки при продължителна недостъпност на услугата. Когато броят на грешките надхвърли прага, Circuit Breaker преминава в състояние OPEN и незабавно връща грешка без да изпълнява заявката, давайки на сървъра време за възстановяване.

В мобилните приложения Circuit Breaker е особено полезен при недостъпност на API поради планирана поддръжка или мрежови повреди на оператора. Без него приложението ще консумира батерия и трафик за безкрайни повторни опити, влошавайки потребителското изживяване и намалявайки времето за работа на устройството с батерия.

Схема на състоянията на Circuit Breaker

Три състояния на Circuit Breaker: CLOSED (нормална работа, заявките се изпълняват), OPEN (отказ, заявките се блокират) и HALF_OPEN (тестова заявка за проверка на възстановяването). След определено време в състояние OPEN, превключвателят преминава в HALF_OPEN и изпълнява една заявка — при успех се връща в CLOSED, при неуспех — в OPEN.

kotlin
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
        }
    }
}

Имплементацията на Circuit Breaker в Kotlin съдържа брояч на грешки и таймер за възстановяване. Методът protect проверява текущото състояние преди изпълнение на блокираната заявка и актуализира брояча на грешки при повреди. След достигане на прага failureThreshold, всички заявки незабавно се отхвърлят до изтичане на timeoutMs.

Retry Policy в мобилни приложения

Мобилните мрежи имат характеристики, които правят Retry Policy особено важна. Превключването между Wi-Fi и мобилни данни, загубата на сигнал в метрото и тунелите, временни блокировки на ниво оператор — всички тези сценарии водят до грешки на заявки, които се обработват успешно чрез повторни опити.

На Android, библиотеката Retrofit и OkHttp предоставят вграден механизъм RetryPolicy чрез Interceptor. На iOS, проблемът се решава чрез URLSessionConfiguration и персонализирано делегиране. За крос-платформена разработка, Ktor (KMP) съдържа вградена поддръжка за retry с конфигурируеми стратегии.

Имплементация на iOS с Combine

Combine — рамката на Apple за реактивно програмиране. Операторът retry в Combine повтаря publisher определен брой пъти при грешка, но не позволява конфигуриране на закъснението между повторенията. За пълноценна Retry Policy се използва персонализирана комбинация от catch и flatMap със закъснение.

swift
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()
    }
}

Разширението retryWithBackoff за Publisher в Combine имплементира exponential backoff чрез рекурсивно извикване с намаляване на брояча и удвояване на закъснението. Операторът delay създава пауза между повторенията, а catch прихваща грешката и решава дали да опита отново или да върне failure.

Типични грешки при Retry Policy

Първа грешка — повтаряне на заявки без проверка на идемпотентността. Ако сървърът е създал ресурс, но не е върнал потвърждение поради мрежова повреда, повторната заявка ще създаде дубликат. За POST заявки винаги използвайте идемпотентен ключ (Idempotency-Key) в хедъра или преминете на retry само за GET, PUT и DELETE.

Втора грешка — безкрайни повторения (retry forever). Винаги задавайте максимален брой опити (3-5 за мобилни приложения) и общ таймаут за всички опити. Безкрайните повторения изтощават батерията и създават паразитно натоварване на сървъра, особено при миграция на бази данни или промяна на API.

Трета грешка — игнориране на контекста на приложението. Ако потребителят е затворил приложението или е преминал в фонов режим, активните Retry Policy трябва да бъдат правилно отменени. Използвайте корутини с SupervisorScope или Combine с жизнения цикъл на UI за автоматично отменяне на повторенията при затваряне на екрана.

Четвърта грешка — нелогване на повторните опити. Без логване няма да разберете колко заявки са били повторени, какви грешки са възникнали и колко ефективна е вашата Retry Policy. Добавете метрики: брой повторения, успеваемост след повторение, разпределение на закъсненията. Тези данни ще помогнат за настройване на оптималните параметри на стратегията за конкретното приложение.

Често задавани въпроси

Колко пъти да повтаряме заявка в мобилно приложение?

Оптималният брой повторения — 3-5 опита за повечето сценарии. За фонова синхронизация са допустими 5-7 опита, за интерактивни заявки (например изпращане на формуляр) — не повече от 3. По-големият брой повторения не увеличава вероятността за успех, но изразходва батерията и трафика на потребителя.

Какво е exponential backoff с прости думи?

Exponential backoff — удвояване на закъснението между повторните опити: 1 секунда, 2, 4, 8, 16 и така нататък. Ако сървърът е претоварен, кратката пауза между първите повторения му позволява да отговори бързо, а нарастващата пауза с всеки следващ опит дава на сървъра все повече време за възстановяване.

Кои HTTP статус кодове си струва да се повтарят?

Повтаряйте само временни грешки: 408 (Request Timeout), 429 (Too Many Requests), 502 (Bad Gateway), 503 (Service Unavailable), 504 (Gateway Timeout). Грешките 4xx (освен 408 и 429) показват проблеми на клиента — повтарянето им няма смисъл и може да бъде опасно за данните на потребителя.

Каква е разликата между Retry Policy и Circuit Breaker?

Retry Policy управлява повторението на една заявка при грешка. Circuit Breaker управлява състоянието на връзката с услугата: при натрупване на грешки отваря веригата (OPEN) и не допуска нови заявки. Retry работи на ниво отделно повикване, Circuit Breaker — на ниво интеграция с услугата.

Как да тестваме Retry Policy на мобилни устройства?

За тестване на Retry Policy използвайте NetworkInterceptor (OkHttp) на Android и URLProtocol (URLSession) на iOS за симулиране на мрежови повреди. Задайте параметри: честота на грешките, продължителност на недостъпността и кодове за отговор. Единични тестове с MockWebServer (OkHttp) или OHHTTPStubs (iOS) проверяват логиката на повторение без реална мрежа.

Резюме

  • Retry Policy — стратегия за автоматично повторение на мрежови заявки при временни повреди с конфигурируеми параметри на закъснение и брой опити.
  • Exponential backoff с jitter — основната стратегия за мобилни приложения, намаляваща натоварването на сървъра при масови повреди и предотвратяваща ефекта thundering herd.
  • Идемпотентност — задължително условие за безопасно повторение на не-GET заявки: без нея повторението създава дубликати на данни или нежелани странични ефекти.
  • Circuit Breaker допълва Retry Policy, предотвратявайки безкрайни повторения при продължителна недостъпност на услугата и спестявайки ресурси на устройството.
  • Класификация на грешките — разделяне на retriable (503, 502, timeout) и non-retriable (400, 401, 403) е критично за правилната работа на политиката за повторение.
  • Максимум 3-5 повторения в интерактивни сценарии и до 7 за фонова синхронизация — оптимална стойност за мобилни приложения според Google Developer Relations.
  • Препоръка — внедрете Retry Policy с exponential backoff, Circuit Breaker и логване за всички мрежови заявки в мобилното приложение.

Ще разработим мобилно приложение под ключ

IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.

Обсъдете проекта

Прочетете също