Yeda AI Tips · #158

English

Nunca Escribas tu Propia Lógica de Reintentos

Tu bucle de reintentos está reintentando errores que nunca pueden funcionar. Un 500 probablemente se resuelva en el próximo intento; un 400, 401 o 422 va a fallar exactamente igual todas las veces — así que un for attempt in range(5) ingenuo solo multiplica por cinco la misma petición condenada, satura un servicio que ya está sufriendo y quema tu presupuesto de latencia sin ningún beneficio.

Por qué fallan los reintentos hechos a mano

El bucle de tres líneas que todos escriben acierta en lo fácil y falla en lo difícil:

La matemática del backoff, el jitter y el estado del circuit breaker son lo bastante sutiles como para que una librería probada lo haga mejor que el código que escribes contra reloj.

La regla: reintenta lo transitorio, salta los errores del cliente

EstadoSignificado¿Reintentar?
408, 429, 500, 502, 503, 504Timeout, límite de tasa, error del servidorSí — transitorio
Conexión reiniciada / DNS / timeout de socketBache de redSí — transitorio
400, 401, 403, 404, 422Petición inválida, auth, no encontrado, validaciónNo — permanente

La única excepción que conviene saber: 429 Too Many Requests es un 4xx pero es reintentable — respeta su cabecera Retry-After en vez de reintentar a ciegas.

Usa una librería

Python — tenacity:

from tenacity import (retry, stop_after_attempt,
                      wait_random_exponential, retry_if_exception_type)

@retry(
    retry=retry_if_exception_type(TransientError),  # skip 4xx
    wait=wait_random_exponential(multiplier=1, max=60),  # backoff + jitter
    stop=stop_after_attempt(5),
)
def call_api():
    ...

wait_random_exponential te da backoff exponencial y jitter en una sola estrategia; retry_if_exception_type es donde filtras solo los errores transitorios.

JavaScript — p-retry: lanza AbortError para detenerte de inmediato ante un error del cliente, sin consumir los intentos restantes.

import pRetry, {AbortError} from 'p-retry';

await pRetry(async () => {
  const res = await fetch(url);
  if (res.status >= 400 && res.status < 500 && res.status !== 429) {
    throw new AbortError(res.statusText); // permanente — detente ya
  }
  if (!res.ok) throw new Error(res.statusText); // transitorio — reintenta
  return res.json();
}, {retries: 5, factor: 2});

Sección avanzada: hacer que los reintentos sean realmente seguros

Un reintento reenvía una petición que el servidor quizá ya procesó. Eso solo es seguro si la operación es idempotente — ejecutarla dos veces tiene el mismo efecto que ejecutarla una vez.

Reintenta lo transitorio, salta el 4xx, usa claves en tus escrituras y acota el bucle — luego deja que una librería cargue con la matemática.

Recursos

<div class="cta">

¿Construyendo una función con IA? Yeda AI diseña, audita y lanza sistemas LLM en producción.

Habla con nosotros · Lee el blog

</div>