Limite de taxa
429, Retry-After e a janela deslizante — e por que o limite é por cliente, não global.
Sem limite, um cliente com um laço errado derruba o serviço para todos os outros. Kiln.rate_limit(maximo, janela) conta pedidos por IP numa janela deslizante e responde 429 com Retry-After:
dataforge
adopt Arcane.Kiln as Kiln
app := Kiln.app()
Kiln.use(app, Kiln.rate_limit(3, 60))
Kiln.get(app, "/busca", lambda req: Kiln.json({"ok": yes}))
status := [Kiln.test(app, "GET", "/busca")["status"] cycle i in range(5)]
assert status is [200, 200, 200, 429, 429]
bloqueado := Kiln.test(app, "GET", "/busca")
assert int(bloqueado["headers"]["Retry-After"]) bigger 0Janela deslizante, e não fixa#
Com janela fixa de um minuto, um cliente manda 60 pedidos às 12:00:59 e mais 60 às 12:01:00 — 120 em um segundo, os dois dentro do limite. A janela deslizante olha sempre os últimos 60 segundos, e esse pico não passa.
| Cliente | Faz | Ao receber 429 |
|---|---|---|
| bem escrito | respeita o Retry-After | espera o que o servidor mandou |
| com recuo exponencial | dobra a espera a cada falha, com sorteio | não sincroniza com os outros |
| mal escrito | repete na hora | fica bloqueado — que é o ponto |