BroadNet
HTTP API & webhooksFiabilidad

Idempotencia y limitación de tasa: claves, 429, Retry-After, RateLimit

Actualizado el 7 min de lecturaBasado en estándares
Respuesta directa

El header Idempotency-Key (borrador IETF) hace seguro un POST reintentado: el servidor almacena el primer resultado por clave dentro de una ventana de deduplicación y lo repite ante cualquier repetición, dando un envío exactamente una vez. La limitación de tasa protege el servicio: las peticiones que exceden el límite reciben 429 Too Many Requests con Retry-After, y los headers RateLimit anuncian la cuota restante para que los clientes se autolimiten.

§01

El header Idempotency-Key

El envío de mensajes es un POST, que no es idempotente, y sin embargo las redes obligan a los clientes a reintentar cuando se pierde una respuesta, creando el clásico doble envío. El borrador Idempotency-Key del grupo de trabajo HTTP-API del IETF estandariza la solución: el cliente genera una clave única (un UUID) por operación lógica y la envía en el header de petición Idempotency-Key. El servidor registra la clave con el resultado de la primera petición, y si ve la misma clave de nuevo no ejecuta una segunda vez: devuelve el resultado almacenado. Así, un reintento tras un timeout está garantizado como inocuo: o bien el primer intento nunca llegó (y este se ejecuta) o bien sí (y su resultado se repite). La clave pertenece a la operación, no a la conexión, así que el cliente reutiliza la misma clave en cada reintento de ese único envío.

POST idempotente con una clave generada por el clientehttp
# Generic IETF-draft example (not the BroadNet API, which takes no
# Idempotency-Key header: see /developers/idempotency)
POST /v1/messages HTTP/1.1
Host: api.example
Idempotency-Key: 8f14e45f-ea7b-4c0f-9b2a-1d2c3e4f5a6b
Content-Type: application/json

{ "to": "+15551234567", "text": "..." }

# first call  -> 202 Accepted, id 01HZY8Q3M6   (executed, stored)
# same key    -> 202 Accepted, id 01HZY8Q3M6   (replayed, not re-sent)
§02

Ventana de deduplicación, repetición de respuesta y conflictos

Una clave de idempotencia no se recuerda para siempre; el servidor la retiene durante una ventana de deduplicación (comúnmente 24 horas), lo bastante para cubrir cualquier reintento realista, y luego la caduca. Dentro de esa ventana, una repetición de la clave reproduce el código de estado y el cuerpo almacenados de forma literal —el mismo 202 y el mismo id de mensaje— para que el cliente vea exactamente lo que habría visto si la primera respuesta hubiera llegado. Dos casos límite exigen un tratamiento explícito. Si una clave se reutiliza con un cuerpo de petición distinto, eso es un fallo del cliente y el servidor devuelve 409 Conflict en vez de enviar en silencio algo incorrecto. Si un reintento llega mientras la primera petición aún está en curso, el servidor devuelve un conflicto o «en progreso» en vez de iniciar una segunda ejecución, para que la concurrencia no pueda vencer la garantía.

Resultados de Idempotency-Key
SituaciónComportamiento del servidorEstado
Nueva claveEjecutar, almacenar clave + resultadoNormal (p. ej. 202)
Clave repetida, mismo cuerpoDevolver la respuesta almacenada, no volver a ejecutarEstado original
Clave repetida, cuerpo diferenteRechazar: clave vinculada a la primera carga útil409 Conflict
Repetición mientras la primera sigue en cursoNo inicie una segunda ejecución409 / en curso
Clave caducada (fuera de la ventana)Tratado como nuevoNormal
§03

Limitación de tasa y 429

Una plataforma de mensajería compartida se protege a sí misma y a otros inquilinos limitando cuán rápido puede llamar cualquier cliente, y señaliza una infracción con un estado específico. RFC 9110 y RFC 6585 definen 429 Too Many Requests para exactamente esto: el cliente ha enviado demasiadas peticiones en un tiempo dado. Un servidor bien educado empareja el 429 con un header Retry-After que indica al cliente cuánto esperar antes de volver a intentarlo (bien un retardo en segundos, bien una fecha HTTP). La obligación del cliente es respetarlo —detenerse, esperar el intervalo indicado y reanudar— en vez de reintentar de inmediato, lo que solo agrava la sobrecarga. Un 429 es transitorio y seguro de reintentar, a diferencia de un 4xx que indica una petición malformada.

429 con headers Retry-After y RateLimithttp
HTTP/1.1 429 Too Many Requests
Retry-After: 2
RateLimit: limit=100, remaining=0, reset=2
RateLimit-Policy: 100;w=1
Content-Type: application/problem+json

{ "type": "https://example/problems/rate-limited",
  "title": "Too Many Requests", "status": 429 }
§04

Los headers RateLimit y RateLimit-Policy

Reaccionar a un 429 a posteriori es un desperdicio; el borrador de headers RateLimit del IETF permite a un cliente ver su presupuesto antes de excederlo. En las respuestas ordinarias el servidor anuncia la cuota actual con un header RateLimit que porta el límite, la asignación restante y los segundos hasta que la ventana se reinicia, y un header RateLimit-Policy que describe la propia política (por ejemplo 100 peticiones por ventana de 1 segundo). Un cliente que los lee puede marcar su propio ritmo —ralentizando a medida que remaining se acerca a cero— y no disparar nunca un 429. Esto convierte la limitación de tasa de un rechazo punitivo a posteriori en una señal cooperativa, que es el sentido mismo de estandarizar los nombres de los headers para que cualquier biblioteca cliente pueda consumirlos.

Headers estándar de señalización de límite de tasa
EncabezadoTransportaEjemplo
429 Too Many RequestsEl estado de límite superadolínea de estado
Retry-AfterCuánto tiempo esperar antes de reintentarRetry-After: 2
RateLimitlimit / remaining / reset para la ventanalimit=100, remaining=17, reset=1
RateLimit-PolicyLa política de cuotas vigente100;w=1 (100 per 1s)
§05

Token bucket y cómo se imponen los límites

El algoritmo de token bucket es el mecanismo habitual detrás de estos headers porque acota la tasa sostenida a la vez que tolera ráfagas breves. Un bucket contiene hasta un número fijo de tokens y se rellena a un ritmo constante; cada petición retira un token, y una petición que encuentra el bucket vacío se rechaza con 429. El tamaño del bucket fija la ráfaga que un cliente puede gastar de una vez y el ritmo de relleno fija el techo a largo plazo, así que un cliente puede enviar una ráfaga rápida tras un periodo inactivo pero no puede superar la media. El valor remaining de RateLimit es en la práctica el conteo de tokens, y reset es cuándo se habrá rellenado el bucket, que es exactamente la información que necesita un cliente que marca su ritmo. Este control de flujo en la capa HTTP es el análogo REST del dimensionado de ventana de SMPP y de la limitación por enquire_link en la sesión binaria.

§06

Contrapresión del cliente

La mitad del cliente de un buen comportamiento ante los límites de tasa es la contrapresión: moldear la carga saliente para que se mantenga dentro del presupuesto anunciado en vez de disparar todo y absorber los 429. En la práctica eso significa un limitador del lado del cliente (un token bucket que refleja el del servidor), leer los headers RateLimit para ajustar el ritmo, y ante un 429 aplicar backoff durante el intervalo de Retry-After con jitter antes de reanudar. Para un envío masivo esto significa dosificar los envíos hasta el techo sostenido en vez de volcarlos, para que la plataforma se mantenga sana y la latencia del propio cliente se mantenga predecible. BroadNet documenta su comportamiento concreto de idempotencia y límite de tasa para desarrolladores.

Preguntas frecuentes

Preguntas frecuentes

¿Qué hace el header Idempotency-Key?

Hace seguro un POST reintentado. El cliente envía una clave única por operación lógica; el servidor ejecuta la primera petición con esa clave y almacena el resultado, y luego repite el resultado almacenado ante cualquier repetición de la misma clave dentro de una ventana de deduplicación. Así, un reintento tras una respuesta perdida o bien se ejecuta una vez o bien se repite, nunca duplica el envío. Está especificado en un borrador del grupo de trabajo HTTP-API del IETF.

¿Cuánto tiempo recuerda el servidor una clave de idempotencia?

Durante una ventana de deduplicación —comúnmente unas 24 horas—, lo bastante para cubrir cualquier reintento realista, tras lo cual la clave caduca y una reutilización se trata como nueva. Dentro de la ventana, una repetición de la clave reproduce el código de estado y el cuerpo originales de forma literal en vez de reejecutar.

¿Qué ocurre si reutilizo una clave de idempotencia con un cuerpo distinto?

El servidor la rechaza con 409 Conflict. La clave queda ligada al payload de la primera petición, así que reutilizarla con un cuerpo distinto se trata como un error del cliente en vez de enviar en silencio el mensaje equivocado. Reutiliza la misma clave solo para reintentos de la operación idéntica.

¿Qué debería hacer un cliente al recibir un 429?

Detenerse y respetar el header Retry-After —esperar los segundos indicados (o hasta la fecha dada) y luego reanudar— en vez de reintentar de inmediato, lo que solo agrava la sobrecarga. Un 429 es transitorio y seguro de reintentar una vez transcurrida la espera, idealmente con algo de jitter para que muchos clientes no reanuden al unísono.

¿Para qué sirven los headers RateLimit y RateLimit-Policy?

Permiten a un cliente ver su cuota antes de excederla. RateLimit porta el límite, la asignación restante y el tiempo de reinicio de la ventana actual; RateLimit-Policy describe la política (por ejemplo 100 peticiones por segundo). Un cliente que los lee puede marcar su ritmo y evitar disparar un 429 por completo. Ambos se definen en un borrador del IETF.

¿Cómo se relaciona un token bucket con los headers RateLimit?

El token bucket es el mecanismo de imposición: un bucket de tamaño fijo se rellena a un ritmo constante, cada petición gasta un token y un bucket vacío da un 429. El valor remaining de RateLimit es esencialmente el conteo de tokens actual y reset es cuándo se rellena el bucket, así que un cliente que lee esos headers sabe exactamente cuánta ráfaga y tasa sostenida le quedan.

Referencias

Especificaciones de la fuente

Las normas publicadas en las que se basa esta página. Se abre en una pestaña nueva.

BNMantenido por el equipo de ingeniería BroadNet·Mensajería de nivel empresarial desde 2003.
Colócalo en el cable

Desarrollado con un enlace SMPP real y una API REST.

Solicita acceso de prueba con claves de prueba reales: primero envía a tu propio número verificado y, una vez aprobada tu identidad de remitente y las rutas, pasa a producción en más de 200 países.