Retry Policy en el desarrollo móvil — esencia, estrategias y principios

Autor: IT Sectr Publicado: 2026-03-11 Tiempo de lectura: 10 min

Retry Policy — política de reintentos — es un conjunto de reglas que determinan cuándo y cómo una aplicación móvil reintenta automáticamente las llamadas de red fallidas. Con conexiones inestables o errores temporales del servidor, una política de reintentos bien diseñada mejora la confiabilidad de la aplicación sin intervención del usuario. Según una investigación de Google Developer Relations (2025), la implementación correcta de Retry Policy reduce el porcentaje de solicitudes perdidas en un 40–60% en aplicaciones móviles con operaciones de red frecuentes.

Ideas clave

  • Retry Policy es una estrategia de reintentos automáticos de solicitudes ante fallos de red o errores temporales del servidor.
  • Exponential backoff es un método de aumento de la demora entre reintentos para reducir la carga del servidor.
  • Jitter es una desviación aleatoria de la demora que evita el efecto de manada (thundering herd).
  • Idempotencia es un requisito clave para reintentos seguros: una solicitud repetida no debe causar efectos secundarios.
  • Circuit Breaker es un mecanismo para detener los reintentos durante una indisponibilidad prolongada del servicio para conservar recursos.

¿Qué es Retry Policy?

Retry Policy es una estrategia de software que define el comportamiento del cliente ante un fallo de solicitud de red: qué errores deben reintentarse, cuántas veces, con qué demora y cuándo dejar de intentarlo. En aplicaciones móviles, la política de reintentos es críticamente importante debido a la inestabilidad de las redes móviles y los posibles fallos temporales del servidor.

Una Retry Policy básica incluye tres parámetros: número máximo de reintentos (maxRetries), demora inicial (baseDelay) y la estrategia de backoff. Adicionalmente, se puede especificar una lista de códigos de estado HTTP que deben provocar un reintento y un tiempo de espera para abortar todos los intentos.

Según el libro “Designing Data-Intensive Applications” de Martin Kleppmann, el 50% de los fallos en sistemas distribuidos son temporales y se resuelven con un reintento. Esto convierte a Retry Policy en una de las formas más efectivas y económicas de mejorar la tolerancia a fallos de una aplicación móvil sin cambios en la arquitectura del servidor.

Qué errores se deben reintentar

Los errores temporales (retriable) son el único tipo de fallo al que Retry Policy debe responder. Estos incluyen tiempos de espera de conexión (SocketTimeoutException), indisponibilidad temporal del servidor (HTTP 503, 502) y errores de DNS. Los errores permanentes — HTTP 400, 401, 403, 404 — no deben reintentarse, ya que indican un problema en la solicitud, no en la red o el servidor.

Según el AWS Architecture Blog, la clasificación correcta de errores en retriable y no retriable es la decisión más importante al diseñar una Retry Policy. Reintentar una solicitud no idempotente con HTTP 401 puede llevar al bloqueo de la cuenta, mientras que reintentar HTTP 400 puede crear datos duplicados. Configure siempre explícitamente la lista de códigos para reintentar.

Estrategias básicas de reintento

Intervalo fijo es la estrategia más simple: cada reintento se realiza después del mismo intervalo de tiempo. Por ejemplo, con una demora de 2 segundos, la aplicación reintenta la solicitud después de 2, 2, 2 segundos. El intervalo fijo es simple de implementar y predecible, pero crea una carga uniforme en el servidor durante fallos masivos.

Intervalo incremental — la demora aumenta linealmente con cada reintento: primer reintento después de 1 segundo, segundo después de 2, tercero después de 3, y así sucesivamente. Esta estrategia le da al servidor más tiempo para recuperarse ante fallos repetidos, pero sigue siendo predecible para muchos clientes que fallan simultáneamente.

EstrategiaFórmula de demoraTiempo acumulado (3 intentos)Aplicación
Fijodelay = D3 × DEscenarios simples, tiempos de espera locales
Incrementaldelay = N × D6 × DReducción gradual de carga
Exponencialdelay = D × 2^N7 × DFallos masivos, servicios en la nube
Exponencial + Jitterdelay = random(0, D × 2^N)variableAlta carga, microservicios

La elección de la estrategia depende de la naturaleza de la aplicación. Para tareas en segundo plano de sincronización de datos en dispositivos móviles, la estrategia exponencial con jitter es óptima — proporciona la mayor probabilidad de éxito con la mínima carga en el servidor y el dispositivo del usuario.

Exponential Backoff y Jitter

Exponential backoff es una estrategia en la que la demora entre reintentos se duplica con cada intento. Si la demora inicial es de 1 segundo, la secuencia de demoras será 1, 2, 4, 8, 16 segundos. Esto le da al servidor un tiempo de recuperación exponencialmente creciente.

Jitter es una desviación aleatoria de la demora que evita solicitudes de reintento simultáneas de múltiples clientes (problema de thundering herd). Sin jitter, mil clientes con la misma Retry Policy reintentarían solicitudes simultáneamente, creando una carga máxima en el servidor. Jitter distribuye los reintentos en el tiempo.

Implementación en Kotlin con corutinas

Las corutinas de Kotlin permiten implementar exponential backoff con jitter sin bloquear el hilo principal. La función retry de kotlinx-coroutines acepta una condición de reintento y un bloque con el cuerpo de la solicitud, manejando automáticamente las demoras y el número de intentos.

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!!)
}

La función executeWithRetry toma una lambda con una llamada de red y la ejecuta con exponential backoff y jitter. Si el error no es retriable o se excede el número máximo de intentos, la función devuelve un error. La demora se multiplica por un factor aleatorio de 0.5 a 1.5 para una distribución uniforme de los reintentos.

Circuit Breaker y cómo detener los reintentos

Circuit Breaker es un patrón de diseño que evita solicitudes de reintento infinitas durante una indisponibilidad prolongada del servicio. Cuando el número de errores supera un umbral, Circuit Breaker pasa al estado OPEN y devuelve inmediatamente un error sin ejecutar la solicitud, dando tiempo al servidor para recuperarse.

En aplicaciones móviles, Circuit Breaker es especialmente útil cuando una API no está disponible debido a mantenimiento planificado o fallos de red del operador. Sin él, la aplicación consumiría batería y tráfico en intentos de reintento infinitos, degradando la experiencia del usuario y reduciendo la autonomía del dispositivo.

Máquina de estados de Circuit Breaker

Circuit Breaker tiene tres estados: CLOSED (funcionamiento normal, las solicitudes se ejecutan), OPEN (fallo, las solicitudes se bloquean) y HALF_OPEN (solicitud de prueba para verificar la recuperación). Después de un tiempo de espera determinado en el estado OPEN, el interruptor pasa a HALF_OPEN y ejecuta una solicitud — si tiene éxito, vuelve a CLOSED; si falla, a 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
        }
    }
}

La implementación de Circuit Breaker en Kotlin contiene un contador de errores y un temporizador de recuperación. El método protect verifica el estado actual antes de ejecutar la solicitud envuelta y actualiza el contador de errores en caso de fallo. Después de alcanzar el failureThreshold, todas las solicitudes se rechazan inmediatamente hasta que expire timeoutMs.

Retry Policy en aplicaciones móviles

Las redes móviles tienen características que hacen que Retry Policy sea especialmente importante. El cambio entre Wi-Fi y datos móviles, la pérdida de señal en metros y túneles, los bloqueos temporales a nivel de operador — todos estos escenarios provocan fallos de solicitud que pueden manejarse exitosamente con reintentos.

En Android, la biblioteca Retrofit y OkHttp proporcionan un mecanismo de reintento integrado a través de Interceptor. En iOS, la tarea se resuelve mediante URLSessionConfiguration y delegación personalizada. Para el desarrollo multiplataforma, Ktor (KMP) incluye soporte integrado de reintento con estrategias configurables.

Implementación en iOS con Combine

Combine es el framework de Apple para programación reactiva. El operador retry en Combine repite el publisher un número especificado de veces al producirse un error, pero no permite configurar la demora entre reintentos. Para una Retry Policy completa, se utiliza una combinación personalizada de catch y flatMap con demora.

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

La extensión retryWithBackoff para Publisher en Combine implementa exponential backoff mediante llamadas recursivas con disminución del contador y duplicación de la demora. El operador delay crea una pausa entre reintentos, mientras que catch intercepta el error y decide si reintentar o devolver un fallo.

Errores típicos en Retry Policy

El primer error — reintentar solicitudes sin verificar la idempotencia. Si el servidor creó un recurso pero no devolvió confirmación debido a un fallo de red, un reintento creará un duplicado. Para solicitudes POST, utilice siempre una clave de idempotencia (Idempotency-Key) en el encabezado o limite los reintentos solo a GET, PUT y DELETE.

El segundo error — reintentar indefinidamente. Establezca siempre un número máximo de intentos (3–5 para aplicaciones móviles) y un tiempo de espera total para todos los intentos. Los reintentos infinitos agotan la batería y crean una carga parásita en el servidor, especialmente durante migraciones de bases de datos o cambios de API.

El tercer error — ignorar el contexto de la aplicación. Si el usuario cerró la aplicación o pasó a segundo plano, las Retry Policy activas deben cancelarse correctamente. Use corutinas con SupervisorScope o Combine con el ciclo de vida de la UI para la cancelación automática de reintentos al cerrar la pantalla.

El cuarto error — no registrar los intentos de reintento. Sin registros, no sabrá cuántas solicitudes se reintentaron, qué errores ocurrieron y qué tan efectiva es su Retry Policy. Agregue métricas: número de reintentos, éxito después del reintento, distribución de demoras. Estos datos ayudarán a ajustar los parámetros óptimos de la estrategia para su aplicación específica.

Preguntas frecuentes

¿Cuántas veces debo reintentar una solicitud en una aplicación móvil?

El número óptimo de reintentos es de 3 a 5 intentos para la mayoría de los escenarios. Para la sincronización en segundo plano, son aceptables de 5 a 7 intentos; para solicitudes interactivas (por ejemplo, envío de formularios), no más de 3. Un número mayor de reintentos no aumenta la probabilidad de éxito, pero consume la batería y el tráfico de datos del usuario.

¿Qué es exponential backoff en términos simples?

Exponential backoff es la duplicación de la demora entre intentos de reintento: 1 segundo, 2, 4, 8, 16 y así sucesivamente. Si el servidor está sobrecargado, la pausa corta entre los primeros reintentos le permite responder rápidamente, mientras que la pausa creciente con cada reintento posterior le da al servidor más tiempo para recuperarse.

¿Qué códigos de estado HTTP se deben reintentar?

Reintente solo errores temporales: 408 (Request Timeout), 429 (Too Many Requests), 502 (Bad Gateway), 503 (Service Unavailable), 504 (Gateway Timeout). Los errores 4xx (excepto 408 y 429) indican problemas del cliente — reintentarlos no tiene sentido y puede ser peligroso para los datos del usuario.

¿En qué se diferencia Retry Policy de Circuit Breaker?

Retry Policy gestiona el reintento de una sola solicitud ante un fallo. Circuit Breaker gestiona el estado de la conexión con un servicio: cuando se acumulan errores, abre el circuito (OPEN) y bloquea nuevas solicitudes. Retry funciona a nivel de llamada individual, Circuit Breaker a nivel de integración con el servicio.

¿Cómo probar Retry Policy en dispositivos móviles?

Para probar Retry Policy, use NetworkInterceptor (OkHttp) en Android y URLProtocol (URLSession) en iOS para simular fallos de red. Configure parámetros: frecuencia de errores, duración de la indisponibilidad y códigos de respuesta. Las pruebas unitarias con MockWebServer (OkHttp) u OHHTTPStubs (iOS) verifican la lógica de reintentos sin red real.

Resumen

  • Retry Policy es una estrategia de reintentos automáticos de solicitudes de red ante fallos temporales con parámetros configurables de demora y número de intentos.
  • Exponential backoff con jitter es la estrategia básica para aplicaciones móviles, que reduce la carga del servidor durante fallos masivos y evita el efecto de thundering herd.
  • Idempotencia es una condición obligatoria para reintentar solicitudes que no sean GET: sin ella, un reintento crea datos duplicados o efectos secundarios no deseados.
  • Circuit Breaker complementa a Retry Policy evitando reintentos infinitos durante una indisponibilidad prolongada del servicio y conservando los recursos del dispositivo.
  • Clasificación de errores en retriable (503, 502, timeout) y no retriable (400, 401, 403) es críticamente importante para el correcto funcionamiento de la política de reintentos.
  • Máximo 3–5 reintentos en escenarios interactivos y hasta 7 para sincronización en segundo plano es el valor óptimo para aplicaciones móviles según Google Developer Relations.
  • Recomendación — implemente Retry Policy con exponential backoff, Circuit Breaker y registro para todas las solicitudes de red en aplicaciones móviles.

Desarrollaremos una aplicación móvil llave en mano

IT Sectr crea aplicaciones para iOS y Android para startups y empresas desde 2017. Le asesoraremos y le propondremos la mejor solución.

Discutir el proyecto

Lea también