Técnico 20 de abr. de 2026 · 6 min de lectura

Límites de peticiones y reintentos: buenas prácticas al llamar a una API de moderación

Backoff exponencial, jitter, circuit breakers y qué hacer cuando la API no está disponible un momento. Para que tu aplicación aguante.

Eduardo Lázaro
Eduardo Lázaro
Fundador de ToxicFilter
Límites de peticiones y reintentos: buenas prácticas al llamar a una API de moderación

Llamar a una API de moderación en producción es como llamar a cualquier otro servicio de terceros en producción: a veces falla. La cuestión es si tu aplicación sabe degradarse sin romperse, machaca al proveedor hasta empeorar la caída o descarta peticiones de usuarios en silencio. Este artículo es una lista de comprobación para escribir un cliente que se comporte como debe.

1. Respeta el límite antes de chocar con él

Toda API de moderación limita las peticiones. La mayoría indica en las cabeceras de cada respuesta cuánto margen te queda:

X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 47
X-RateLimit-Reset: 1716480000

Un buen cliente las lee en cada respuesta y aplica throttling en el lado del cliente cuando Remaining baja de un umbral de seguridad. La alternativa ingenua, lanzar peticiones hasta recibir un 429, es una forma estupenda de hacerte un DoS a ti mismo.

2. Reintenta solo los errores que toca

Una clasificación rápida de las respuestas HTTP:

Código ¿Reintentar? Por qué
2xx No Éxito
400 No Enviaste una petición mal formada. Reintentar no ayuda.
401, 403 No Problema de autenticación. Avisa a quien esté de guardia, no reintentes.
402 No Sin créditos. La solución es un plan mayor o el mes que viene, no dentro de un minuto.
404 No Normalmente un error de URL o de configuración.
408, 425, 429 Sí, con backoff Transitorio.
500, 502, 503, 504 Sí, con backoff Del lado del servidor, probablemente transitorio.

Lee la cabecera Retry-After si viene: te indica cuándo cree el servidor que debes volver.

3. Backoff exponencial con jitter

Los reintentos lineales provocan estampidas después de una caída: todo el mundo reintenta a los mismos intervalos y vuelve a tumbar el servicio en cuanto se recupera. Usa backoff exponencial con jitter aleatorio:

function backoffMs(attempt: number): number {
    const base = 200;          // 200ms
    const cap = 10_000;        // cap at 10s
    const exp = Math.min(cap, base * 2 ** attempt);
    return Math.random() * exp; // "full jitter"
}

// attempt 0 -> 0 to 200ms
// attempt 1 -> 0 to 400ms
// attempt 2 -> 0 to 800ms
// attempt 3 -> 0 to 1.6s
// attempt 4 -> 0 to 3.2s

El "full jitter" (aleatorio entre 0 y el exponencial con tope) reparte mejor los reintentos que el "equal jitter" o que no usar jitter. Limita los intentos a entre tres y cinco salvo que tengas una buena razón para seguir.

4. Claves de idempotencia, para ir sobre seguro

Que un reintento envíe dos veces la misma comprobación no es problema, porque el resultado es el mismo. Pero si la moderación forma parte de una operación de escritura más amplia (guardar un comentario, banear a un usuario), no te interesa que los efectos secundarios se ejecuten dos veces. Usa claves de idempotencia:

POST /api/v1/text
Idempotency-Key: 7f3c9e2a-1b8d-4e6f-9a1b-2c8d7e3f4a5b

El servidor devuelve la misma respuesta para la misma clave durante un periodo (normalmente 24 horas). Genera la clave una vez por acción del usuario, no por intento HTTP.

5. Circuit breakers para caídas prolongadas

Si la API está caída, reintentar cada llamada añade carga sin aportar nada. Un circuit breaker detecta un fallo sostenido (por ejemplo, >50% de errores en 30 segundos) y se salta la API por completo durante un periodo de enfriamiento. Mientras el breaker está abierto:

  • Pasas a un comportamiento por defecto más seguro, normalmente "dejar pasar el contenido pero marcarlo como no comprobado".
  • Después, revisas a mano una parte mayor de ese tráfico.
  • Avisas a quien esté de guardia.

Bibliotecas como resilience4j (JVM) u opossum (Node) lo hacen por ti; en Laravel son unas pocas líneas sobre la caché.

6. Timeouts, más ajustados de lo que crees

Una API de moderación que normalmente responde en 50 ms no debería tener un timeout de 30 segundos. Pon el timeout del cliente en dos o tres veces tu p99, no en "lo que traiga por defecto la biblioteca HTTP". Un timeout mal configurado es la razón más común por la que una dependencia lenta acaba en una caída en cascada.

import ToxicFilter from 'toxicfilter-sdk';

const tf = new ToxicFilter(process.env.TOXICFILTER_KEY, {
    timeout: 3_000,          // milliseconds, not 30_000
    retries: 2,              // 429 and 5xx only, with a growing wait; never a 402
});

Ajústalo a la llamada más lenta que hagas. Una comprobación que resuelven los detectores gratuitos vuelve en torno a un milisegundo más la red; una que lee el modelo tarda más, así que un timeout pensado para la primera cortará la segunda.

7. Decide el plan B antes del incidente

Cuando la API de moderación no responde y tu circuit breaker se abre, ¿qué hace tu aplicación?

  • Fail-open: dejar pasar el contenido sin moderar. Tu aplicación sigue en pie. Riesgo: los atacantes aprenden a atacar durante las caídas.
  • Fail-closed: rechazar todo el contenido. Tu aplicación está a salvo. Riesgo: rompes tu propio producto con cualquier incidente del proveedor.
  • Modo degradado: recurrir a un filtro local de palabras clave o a un clasificador ligero autoalojado. Término medio; más trabajo de ingeniería.

No hay una respuesta que valga para todos. Lo que importa es que la decisión se tome de antemano, se documente en un runbook y el comportamiento se pruebe con inyección de fallos. El peor momento para decidir tu política de respaldo es a las 3 de la mañana durante la caída de verdad.

Pruébalo con tu tráfico real

Permitir, revisar o bloquear, y el motivo explicado. En el plan gratuito: 2.000 créditos al mes, sin tarjeta. Una comprobación cuesta 1 crédito, unos 8 si la lee el modelo y unos 10 por imagen.