BroadNet
HTTP API & webhooksFiabilidade

Idempotência e rate limiting: chaves, 429, Retry-After, RateLimit

Atualizado em 7 min de leituraBaseado em padrões
Resposta direta

O header Idempotency-Key (draft IETF) torna seguro um POST repetido: o servidor guarda o primeiro resultado por chave dentro de uma janela de desduplicação e reproduz-no em qualquer repetição, dando submissão exactly-once. O rate limiting protege o serviço: os pedidos acima do limite recebem 429 Too Many Requests com Retry-After, e os headers RateLimit anunciam a quota restante para que os clientes se autolimitem.

§01

O header Idempotency-Key

A submissão de mensagens é um POST, que não é idempotente, mas as redes obrigam os clientes a repetir quando uma resposta se perde — criando o clássico envio duplicado. O draft Idempotency-Key do grupo de trabalho HTTP-API da IETF normaliza a solução: o cliente gera uma chave única (um UUID) por operação lógica e envia-a no header de pedido Idempotency-Key. O servidor regista a chave com o desfecho do primeiro pedido e, se voltar a ver a mesma chave, não executa uma segunda vez — devolve o resultado guardado. Assim, um retry após um timeout é garantidamente inócuo: ou a primeira tentativa nunca chegou (e esta executa) ou chegou (e o seu resultado é reproduzido). A chave pertence à operação, não à ligação, pelo que o cliente reutiliza a mesma chave em cada retry desse mesmo envio.

POST idempotente com uma chave gerada pelo 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

Janela de desduplicação, replay da resposta e conflitos

Uma chave de idempotência não é lembrada para sempre; o servidor guarda-a durante uma janela de desduplicação (habitualmente 24 horas) o suficiente para cobrir qualquer retry realista e depois expira-a. Dentro dessa janela, uma repetição da chave reproduz o status code e o corpo guardados textualmente — o mesmo 202 e o mesmo message id — para que o cliente veja exatamente o que teria visto se a primeira resposta tivesse chegado. Dois casos-limite precisam de tratamento explícito. Se uma chave for reutilizada com um corpo de pedido diferente, isso é um bug do cliente e o servidor devolve 409 Conflict em vez de enviar em silêncio a coisa errada. Se um retry chegar enquanto o primeiro pedido ainda está em curso, o servidor devolve um conflito ou 'in progress' em vez de iniciar uma segunda execução, para que a concorrência não derrote a garantia.

Desfechos do Idempotency-Key
SituaçãoComportamento do servidorStatus
Nova chaveExecutar, armazenar chave + resultadoNormal (ex: 202)
Mesma chave, mesmo corpoReenviar a resposta armazenada, não executar novamenteStatus original
Mesma chave, corpo diferenteRejeitar — chave vinculada ao primeiro payload409 Conflict
Repetição enquanto a primeira ainda está em andamentoNão inicie uma segunda execução409 / em andamento
Chave expirada (fora da janela)Tratado como novoNormal
§03

Rate limiting e 429

Uma plataforma de mensagens partilhada protege-se a si e aos outros tenants limitando a rapidez com que qualquer cliente pode chamar, e sinaliza uma violação com um status específico. As RFC 9110 e RFC 6585 definem 429 Too Many Requests exatamente para isto: o cliente enviou pedidos a mais num dado intervalo de tempo. Um servidor bem-comportado emparelha o 429 com um header Retry-After que diz ao cliente quanto esperar antes de tentar de novo (seja um atraso em segundos, seja uma data HTTP). A obrigação do cliente é honrá-lo — parar, esperar o intervalo indicado e depois retomar — em vez de repetir de imediato, o que só aprofunda a sobrecarga. Um 429 é transitório e seguro de repetir, ao contrário de um 4xx que indica um pedido malformado.

429 com headers Retry-After e 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

Headers RateLimit e RateLimit-Policy

Reagir a um 429 depois do facto é um desperdício; o draft RateLimit-headers da IETF permite a um cliente ver o seu orçamento antes de o exceder. Nas respostas comuns, o servidor anuncia a quota atual com um header RateLimit que transporta o limite, a permissão restante e os segundos até o reset da janela, e um header RateLimit-Policy que descreve a própria política (por exemplo 100 pedidos por janela de 1 segundo). Um cliente que os leia pode regular-se — abrandando à medida que remaining se aproxima de zero — e nunca disparar um 429. Isto transforma o rate limiting de uma rejeição punitiva a posteriori num sinal cooperativo, que é todo o propósito de normalizar os nomes dos headers para que qualquer biblioteca de cliente os possa consumir.

Headers padrão de sinalização de rate limit
CabeçalhoTransportaExemplo
429 Too Many RequestsO status de limite excedidolinha de status
Retry-AfterQuanto tempo esperar antes de tentar novamenteRetry-After: 2
RateLimitlimite / restante / reset para a janelalimit=100, remaining=17, reset=1
RateLimit-PolicyA política de quotas em vigor100;w=1 (100 per 1s)
§05

Token bucket e como os limites são impostos

O algoritmo token-bucket é o mecanismo habitual por trás destes headers porque limita a taxa sustentada tolerando ao mesmo tempo bursts curtos. Um bucket contém até um número fixo de tokens e reabastece a um ritmo estável; cada pedido remove um token, e um pedido que encontre o bucket vazio é rejeitado com 429. O tamanho do bucket define o burst que um cliente pode gastar de uma vez e o ritmo de reabastecimento define o teto de longo prazo, pelo que um cliente pode enviar um burst rápido após um período inativo mas não pode exceder a média. O valor remaining do RateLimit é efetivamente a contagem de tokens, e reset é quando o bucket estará reabastecido — que é exatamente a informação de que um cliente regulado precisa. Este controlo de fluxo na camada HTTP é o análogo REST do dimensionamento de janela SMPP e do throttling por enquire_link na sessão binária.

§06

Backpressure do cliente

A metade do cliente do bom comportamento de rate limit é a backpressure: moldar a carga de saída para que fique dentro do orçamento anunciado em vez de disparar tudo e absorver 429s. Na prática, isso significa um limitador do lado do cliente (um token bucket a espelhar o do servidor), ler os headers RateLimit para ajustar o ritmo e, num 429, recuar durante o intervalo Retry-After com jitter antes de retomar. Para um envio em massa, significa medir as submissões ao teto sustentado em vez de as despejar, para que a plataforma se mantenha saudável e a própria latência do cliente se mantenha previsível. A BroadNet documenta o seu comportamento concreto de idempotência e rate limit para programadores.

Perguntas frequentes

Perguntas frequentes

O que faz o header Idempotency-Key?

Torna seguro um POST repetido. O cliente envia uma chave única por operação lógica; o servidor executa o primeiro pedido com essa chave e guarda o resultado, reproduzindo depois o resultado guardado em qualquer repetição da mesma chave dentro de uma janela de desduplicação. Assim, um retry após uma resposta perdida ou executa uma vez ou reproduz — nunca envia em duplicado. Está especificado num draft do grupo de trabalho HTTP-API da IETF.

Durante quanto tempo o servidor lembra uma chave de idempotência?

Durante uma janela de desduplicação — habitualmente cerca de 24 horas — o suficiente para cobrir qualquer retry realista, após o que a chave expira e uma reutilização é tratada como nova. Dentro da janela, uma repetição da chave reproduz o status code e o corpo originais textualmente em vez de reexecutar.

O que acontece se reutilizar uma chave de idempotência com um corpo diferente?

O servidor rejeita-a com 409 Conflict. A chave está ligada ao payload do primeiro pedido, pelo que reutilizá-la com um corpo diferente é tratado como um erro de cliente em vez de enviar em silêncio a mensagem errada. Reutilize a mesma chave apenas para retries da operação idêntica.

O que deve um cliente fazer quando recebe um 429?

Parar e honrar o header Retry-After — esperar os segundos indicados (ou até à data dada) e depois retomar — em vez de repetir de imediato, o que só aprofunda a sobrecarga. Um 429 é transitório e seguro de repetir depois de decorrida a espera, idealmente com algum jitter para que muitos clientes não retomem em sincronia.

Para que servem os headers RateLimit e RateLimit-Policy?

Permitem a um cliente ver a sua quota antes de a exceder. O RateLimit transporta o limite, a permissão restante e o tempo de reset da janela atual; o RateLimit-Policy descreve a política (por exemplo 100 pedidos por segundo). Um cliente que os leia pode regular-se e evitar disparar um 429. Ambos estão definidos num draft da IETF.

Como se relaciona um token bucket com os headers RateLimit?

O token bucket é o mecanismo de imposição: um bucket de tamanho fixo reabastece a um ritmo estável, cada pedido gasta um token, e um bucket vazio dá um 429. O valor remaining do RateLimit é essencialmente a contagem atual de tokens e reset é quando o bucket reabastece — pelo que um cliente que leia esses headers sabe exatamente quanto burst e taxa sustentada lhe restam.

Referências

Especificações de origem

Os padrões publicados nos quais esta página se baseia. Abre num novo separador.

BNMantido pela equipa de engenharia BroadNet·Mensagens de nível de operadora desde 2003
Coloque-o no fio.

Construa com uma vinculação SMPP real e uma API REST.

Solicite acesso de teste com chaves de teste reais: envie primeiro para o seu próprio número verificado e, em seguida, passe para o ambiente de produção em mais de 200 países assim que a sua identidade de remetente e rotas forem aprovadas.