Diseñe para variabilidad, no para el promedio
Mida DNS, conexión, TLS, upload, procesamiento, first byte, descarga, pérdida, reconexión y cambios de radio. Segmente por país, operador/ASN, red, app, dispositivo, endpoint, payload e intento. p50 oculta a quien cruza repetidamente el timeout.
RTT altoCada handshake y dependencia secuencial es costosa. Reutilice conexión, reduzca llamadas y agrupe con límites.
Pérdida y cambio de rutaLa conexión se detiene o reinicia y el cliente no sabe si el write confirmó.
Ancho de banda variableUna respuesta pequeña funciona; medios o listas ilimitadas fallan a mitad.
Disponibilidad intermitenteLa app alterna online, captive, degradada, background y offline; la intención sobrevive al proceso.
Asigne un deadline integral
La operación necesita un presupuesto, no 30 segundos por salto. Reserve DNS/connect/TLS, primer intento, retry opcional, parsing y UI. Propague el saldo downstream y cancele trabajo abandonado. Separe timeout de conexión y request/idle.
DNS
Connect
TLS
Try 1
Jitter
Try 2
Límite
Parse
UI
Retry depende de método, falla y presupuesto
Repita GET/HEAD ante fallas transitorias. PUT/DELETE pueden ser idempotentes por contrato, pero una implementación puede disparar efectos externos. No repita POST/PATCH sin idempotency contract. Validación, autenticación, autorización, conflicto y not-found permanente no son pérdida de paquetes.
Backoff exponencial acotado con full jitterT+0Intento 1Envíe request ID, deadline e idempotency key cuando corresponda.
falla transitoria → aleatorio 0..base
T+Δ1Intento 2Reutilice ID lógico y deténgase si presupuesto/política no permiten.
aleatorio 0..min(cap, base × 2²)
T+Δ2Intento finalDevuelva estado recuperable, encole o muestre falla. Nunca repita sin límite.
Ubique retries en una sola capa
SDK 3x, gateway 3x y servicio 3x producen 27 llamadas. Elija la capa que conoce semántica y presupuesto. Use retry quota/token bucket, límites, full jitter, Retry-After y desactive ante falla sostenida.
| Resultado | Interpretación | Política | Contrato servidor | Evitar |
|---|
| Conexión perdida sin respuesta | Outcome del write desconocido. | Retry solo seguro/idempotente o keyed. | Estado consultable por key/ID. | Crear compra duplicada. |
| 408 / timeout | No completó en contexto. | Retry acotado si queda budget. | Detener trabajo y deduplicar. | Reiniciar operación larga. |
| 429 / cuota | El caller excedió política. | Respetar tiempo y regular tráfico. | Política legible por máquina. | Todos repiten juntos. |
| 502/503/504 | Upstream, overload o gateway transitorio. | Retry pequeño con jitter; fallback de lectura. | Load shedding y Retry-After. | Retry storm. |
| 409 conflicto | Estado actual rechaza cambio. | Leer y conciliar. | Problem details y revisión. | Sobrescribir concurrencia. |
| 4xx validación/auth | Request o autoridad debe cambiar. | Sin retry de transporte. | Tipo, campos, remedio y request ID. | Gastar batería repitiendo. |
La idempotencia es una máquina de estados
El cliente crea una key de alta entropía ligada a principal y ruta. El servidor guarda key, fingerprint, estado, operación/recurso, resultado, timestamps y expiración. Misma key/payload devuelve outcome original; payload distinto se rechaza. Duplicados concurrentes esperan o reciben “en progreso”. Persista el registro con el efecto de forma atómica.
El trabajo largo es asíncrono
Devuelva 202 Accepted con URL de operación. Exponga pending/running/succeeded/failed/cancelled, tiempos, resultado y problem detail. Polling usa backoff y ETag, o evento firmado. No mantenga una conexión móvil abierta durante minutos.
La paginación comienza con orden estable
Cada lista nace paginada. El cursor liga query, filtros, sort, snapshot/boundary, dirección y última tupla, por ejemplo (updated_at, id). Tokens son opacos e íntegros. Offset sirve para conjuntos pequeños/estáticos; colecciones mutables producen duplicados y saltos.
Permita pedir menos
Use page size acotado, field masks, summaries, filtros, delta sync, updated_since estable y medios separados. El cliente necesita la próxima pantalla accionable, no todo el dominio.
La compresión se negocia y mide
Use Accept-Encoding y Vary: Accept-Encoding. Comprima JSON, texto, protobuf y SVG sobre un umbral. No recomprima JPEG/AVIF/video. Compare Brotli, gzip y Zstandard por tamaño, CPU, batería y latencia.
Caché y revalidación evitan descargas
Use Cache-Control, ETag, If-None-Match y Last-Modified. Separe público/personal, defina Vary y freshness. Datos stale requieren as_of y acciones limitadas. Cache-Status ayuda a depurar.
Las transferencias grandes se reanudan
Upload por partes usa ID, offset/part, checksum, expiración, metadata y finalize. Downloads usan ranges y validators. Repita partes faltantes. tus es una opción establecida. No complete antes de verificar longitud y digest.
La degradación es un contrato de producto
Sirva menosPágina menor, summary, sin thumbnail, menor precisión, enriquecimiento diferido o caché.
Encole intenciónComando local con operation ID, key, versión, expiración, estado y política de conflicto.
Bloquee acciones riesgosasSi auth, precio, stock, saldo o seguridad están stale, permita lectura y bloquee writes irreversibles.
Priorice tráfico centralAuth, seguridad, pago, metadata de sync y texto antes de analytics e imágenes.
Haga load sheddingRechace trabajo opcional temprano y preserve capacidad crítica.
Muestre estado realOffline, sincronizando, pendiente, stale, falló, conflicto y confirmado son distintos.
Use errores legibles por máquina
RFC 9457 define type, title, status, detail e instance. Agregue código estable, campos, retryability, correlation ID y remediación. No exponga stack ni obligue a parsear texto localizado.
El transporte no reemplaza semántica
HTTP/3 sobre QUIC mejora pérdida y cambios; prioridad HTTP comunica urgencia. Reuso, TLS resumption, edge y menos secuencias ayudan. Nada evita efectos duplicados, listas ilimitadas, errores ambiguos o writes stale.
Observe intentos, no solo requests
Trace una operación por operation ID y request ID por intento. Registre timings, bytes, compresión, caché, red, fase del timeout, retry, idempotencia, cursor, stale mode, cola y outcome. Mida amplificación, deduplicación, conclusión por red, datos/batería y p95/p99.
Lo que construiría
SDK con deadline, timeouts, clasificación, full-jitter, quota, keys, polling, cursor, caché condicional, uploads reanudables, outbox, conflictos y telemetría. Servidor con storage idempotente, problem details, load shedding, paginación, field masks, operaciones, ETags, cancelación y trazas por intento.
El principio
Una API confiable no finge que la red es confiable. Vuelve recuperable cada outcome incierto, acota retries, deduplica writes, reanuda transferencias y hace visible el estado degradado.