Em apps iOS, chamadas de rede falham por inúmeras razões: conexão instável, timeout, servidor sobrecarregado. Retry com backoff exponencial e circuit breaker são essenciais para uma experiência resiliente.

Estratégias de Retry

Quando uma requisição falha com erro transitório, podemos repetir após um intervalo crescente. A chave é distinguir erros retryable de erros permanentes.

EstratégiaFórmulaQuando usar
Constantdelay = baseRate limiting (429) com Retry-After header
Lineardelay = attempt * baseDegradação previsível e controlada
Exponentialdelay = base * 2^attemptFalhas transitórias genéricas
Exponential + Jitter(capped + random) / 2Recomendado — evita thundering herd

Status Codes Retryable

Status CodeSignificadoAção
408Request TimeoutRetry — servidor não respondeu a tempo
429Too Many RequestsRetry após Retry-After header
500Internal Server ErrorRetry — pode ser transitório
502Bad GatewayRetry — proxy/load balancer issue
503Service UnavailableRetry — serviço temporariamente indisponível
504Gateway TimeoutRetry — upstream não respondeu

RetryPolicy do IdentityKit

// RetryPolicy — IdentityKit public struct RetryPolicy: Sendable { public let maxAttempts: Int public let baseDelay: TimeInterval public let maxDelay: TimeInterval public func delay(forAttempt attempt: Int) -> TimeInterval { let exponential = baseDelay * pow(2.0, Double(attempt)) let capped = min(exponential, maxDelay) let jitter = Double.random(in: 0...capped) return (capped + jitter) / 2.0 } public func isRetryable(statusCode: Int) -> Bool { switch statusCode { case 408, 429, 500, 502, 503, 504: return true default: return false } } public static let `default` = RetryPolicy( maxAttempts: 3, baseDelay: 1.0, maxDelay: 30.0 ) }
Por que usar (capped + jitter) / 2 em vez de apenas capped + jitter?
A fórmula (capped + jitter) / 2 garante que o delay médio fique próximo ao valor exponencial esperado, mas com variação aleatória. Se usássemos apenas soma, o delay médio seria 1.5x o esperado, desperdiçando tempo. A divisão mantém o comportamento exponencial enquanto distribui os retries no tempo.