Um 429 Too Many Requests é o único código de estado que é sobre si e não sobre o servidor nem sobre aquilo que pediu. Nada se partiu, nada falta, e tem autorização para estar aqui. Simplesmente pediu mais vezes do que alguém achou razoável, e a resposta é uma recusa com um relógio agarrado.

Tudo o resto na gama 4xx descreve um pedido concreto: este estava malformado, este não trazia credenciais, este não nomeava nada. Um 429 descreve um padrão. É o servidor a falar do seu comportamento ao longo de uma janela de tempo, e é por isso que pode chegar em resposta a um pedido perfeitamente correcto que teria funcionado há dez minutos.

O único erro em que tentar de novo piora as coisas

A maioria dos erros premeia uma nova tentativa. Um 503 muitas vezes resolve-se à segunda, e num 500 vale a pena um recarregamento no caso de ter apanhado um mau momento. O instinto costuma estar certo, e aqui está precisamente errado.

Um limitador de taxa conta pedidos. Uma nova tentativa é um pedido. Martelar um serviço que acabou de lhe dizer para abrandar prolonga a janela em que o está a segurar e, em serviços que escalam, transforma um limite de sessenta segundos numa hora ou num bloqueio que alguém tem de levantar à mão. O ciclo de retry ingénuo, aquele sem pausa nenhuma lá dentro, é a forma como um estrangulamento curto se torna uma falha que parece culpa do outro lado.

Portanto um 429 é o erro em que não fazer nada é a decisão activa. Espere que a janela passe, e depois vá outra vez, uma vez.

Os cabeçalhos que dizem quando voltar

Um 429 normalmente traz Retry-After, dando ou um número de segundos ou uma data:

HTTP/1.1 429 Too Many Requests
Retry-After: 60
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1789412400

Retry-After é o normalizado e o único em que pode confiar. A família X-RateLimit-* é uma convenção e não uma especificação: muito usada, escrita de maneiras diferentes por serviços diferentes, e que vale a pena ler quando lá está, porque lhe diz a forma do limite e não apenas o próximo momento em que pode bater à porta.

Esses cabeçalhos são a diferença entre recuar como deve ser e adivinhar. Se está a escrever qualquer coisa que fale com uma API por calendário, leia-os: a um serviço que disse sessenta segundos e leva uma tentativa por segundo está a pedir-se cento e vinte vezes que sirva pedidos que já recusou.

Quando o tráfego não era seu

A parte incómoda de um 429 é que aquilo que é contado raramente é uma pessoa. É um endereço IP, uma chave de API, uma conta ou uma sessão, e cada uma dessas coisas cobre mais do que um de vós.

Um escritório atrás de um único endereço, um café, um operador móvel a fazer NAT à escala de operador, um pipeline de CI a partilhar uma chave com uma equipa, um colega a testar um script contra o mesmo endpoint com as mesmas credenciais. Tudo isso produz um 429 para alguém que não fez nada de invulgar, e nada disso se vê a partir da página de erro.

Daí sai o teste útil. Se um 429 o segue de rede em rede, é a sua conta ou a sua chave; se desaparece com dados móveis, era o endereço de onde vinha. É a mesma pergunta que distinguir o seu bug da falha deles, feita sobre um limite em vez de sobre uma avaria.

Pode ser limitado sem nunca ver um 429

Nada obriga um serviço a usar este código. Muitos devolvem um 403 para que o estrangulamento pareça uma decisão de permissões, alguns devolvem um 503 porque, visto de fora, “agora não” é verdade de qualquer maneira, e uma CDN à frente de uma aplicação responderá muitas vezes com a escolha dela em vez da escolha da aplicação.

Por isso um 429 é, de certa forma, boa notícia: é um serviço a ser específico consigo. A ausência dele não é prova de que não o estejam a limitar, e se um 403 ou um 503 aparece só sob carga e só a partir de um endereço, um limitador é o que há a suspeitar diga o que disser o código.

Se a API é sua

A pergunta que convém responder antes de qualquer afinação é que camada está a contar. Um limite na sua aplicação, um no nginx e um na CDN são três conjuntos de números diferentes, e aquele em que os seus utilizadores batem normalmente não é aquele para onde tem estado a olhar.

Depois mande os cabeçalhos. Um 429 sem Retry-After é um serviço que se recusa a dizer quando, o que deixa cada cliente inventar um backoff, e os que inventam são piores do que o número que lhes teria dado. Ser específico não custa nada.

E tenha cuidado com o que o limite conta. Limites por IP castigam escritórios e redes partilhadas pelo comportamento de uma só pessoa lá dentro, o que é um ticket de suporte que chega como “o vosso site está partido para a nossa equipa inteira”. Limites por conta ou por chave são mais difíceis de implementar e muito mais fáceis de explicar.

Porque é que um 429 é difícil de reconstruir depois

Quando alguém lhe fala dele, a janela já passou e o pedido funciona. O que o fez falhar não foi o pedido mas a companhia dele: os outros noventa e nove que chegaram no mesmo minuto, a maioria de outra pessoa, nenhum deles à sua frente agora.

Session Replay

Extensão gratuita do Chrome. Um clique na página que se está a portar mal captura a captura de ecrã, a consola e o registo de rede, e dá-lhe um link para colar no ticket.

Obter a extensão

O registo de rede é o que torna um 429 investigável: o pedido que falhou, o minuto exacto, e os cabeçalhos de resposta a dizer que limite foi tocado e quanto lhe faltava correr. É a diferença entre um relatório que alguém consegue cruzar com o log de um limitador e uma mensagem a dizer que o site deixou de funcionar durante um bocado esta manhã.

Num parágrafo

Um 429 Too Many Requests significa que pediu vezes demais, o que faz dele o único código de estado sobre o seu comportamento em vez de ser sobre o servidor ou o recurso. É também o único erro em que tentar de novo é activamente contraproducente, porque uma nova tentativa é mais um pedido para o limitador contar: leia Retry-After, espere, e depois vá uma vez. O tráfego que está a ser contado muitas vezes não é o seu, já que os limites se aplicam a endereços e chaves que cobrem escritórios e equipas inteiras, e um telemóvel com dados dir-lhe-á com qual dos dois está a lidar. Se a API é sua, descubra que camada conta, mande sempre Retry-After, e prefira limitar uma chave a limitar um endereço, para que uma pessoa não consiga trancar um edifício inteiro cá fora.