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.
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.
# 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)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.
| Situação | Comportamento do servidor | Status |
|---|---|---|
| Nova chave | Executar, armazenar chave + resultado | Normal (ex: 202) |
| Mesma chave, mesmo corpo | Reenviar a resposta armazenada, não executar novamente | Status original |
| Mesma chave, corpo diferente | Rejeitar — chave vinculada ao primeiro payload | 409 Conflict |
| Repetição enquanto a primeira ainda está em andamento | Não inicie uma segunda execução | 409 / em andamento |
| Chave expirada (fora da janela) | Tratado como novo | Normal |
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.
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 }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.
| Cabeçalho | Transporta | Exemplo |
|---|---|---|
| 429 Too Many Requests | O status de limite excedido | linha de status |
| Retry-After | Quanto tempo esperar antes de tentar novamente | Retry-After: 2 |
| RateLimit | limite / restante / reset para a janela | limit=100, remaining=17, reset=1 |
| RateLimit-Policy | A política de quotas em vigor | 100;w=1 (100 per 1s) |
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.
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
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.
Especificações de origem
Os padrões publicados nos quais esta página se baseia. Abre num novo separador.