uk_sk_…, eles são um contrato
de capacidade. É a única superfície cujo chamador é um programa, e não uma
pessoa: ali a contagem é por chave e os números vão em headers em toda resposta —
o seu cliente consegue se conter em vez de descobrir o limite batendo nele.
Ao ser limitado
429
Retry-After carrega a janela em segundos. Espere; tentar antes só consome a
próxima janela. Na superfície de máquina a janela é de um minuto, então nunca
passa de 60.
Os limites
Autenticação de staff
Convites
Plano de clientes
O limite por chave no boot existe porque a chave publicável é a fronteira de tenant
por onde uma enxurrada chega: bots e tráfego de landing page criariam linhas de
visitante para sempre.
A superfície do próprio contato
Por sessão, não por IP. Atrás do NAT de uma operadora um endereço é milhares de
pessoas, então um balde por IP numa superfície autenticada limita uma multidão
pelo que um deles fez — e a sessão é o que de fato gasta o trabalho. O
/v1/contact/token é a razão de o número existir: cada chamada é um decrypt de
chave e uma assinatura.
A superfície de máquina
Por chave, não por IP. O seu backend chama isso de um endereço de datacenter
que todos os seus servidores compartilham, e não carrega sessão — a chave é a
única coisa que identifica o chamador, e a única sobre a qual você pode agir.
Duas consequências que valem planejamento:
- A sua própria segmentação é o seu isolamento. Uma chave por serviço — o app, o worker, o job noturno — significa que um backfill rodando a todo vapor não consegue limitar o seu caminho de login: os 1000 dele param antes de ter gasto mais de um terço dos 3000 compartilhados. Uma chave para tudo é um balde para tudo.
- Criar chaves não compra cota. O teto do ambiente é o que faz o limite por chave significar algo: a quarta chave divide os mesmos 3000.
As demais rotas autenticadas — a sessão do painel — não têm throttle além dos
endpoints de login acima. A credencial é o portão, e ela é revogável.
Lendo os headers
Toda resposta da superfície de máquina carrega o estado atual, tanto num200
quanto num 429.
RateLimit-* são os do draft da IETF, e os X-RateLimit-* são os que a
maioria dos clientes escritos na última década já lê. Use o que o seu cliente
HTTP entender e ignore o outro.
O único ponto em que elas divergem é o reset, e não é descuido — cada nome
significa o que a sua própria convenção diz. RateLimit-Reset é quantos segundos
esperar; X-RateLimit-Reset é o timestamp até o qual esperar.
X-RateLimit-Scope existe porque há dois tetos em jogo e os números descrevem
aquele que está mais perto de acabar. RateLimit-Limit: 3000 numa chave cujo
limite próprio é 1000 quer dizer que o teto do ambiente é o que está pesando:
outra chave sua está gastando a cota compartilhada.
Falhar aberto, falhar fechado
Duas posturas, escolhidas por endpoint. Os contadores vivem num store compartilhado por todas as instâncias da API. Quando esse store não pode ser alcançado, cada instância passa a contar sozinha — os limites continuam existindo e ficam mais frouxos, em vez de sumirem. Isso é deliberado, e é o único lugar onde esta plataforma não degrada graciosamente. Todo o resto que é opcional se desliga sem a sua dependência; um cadastro público atrás de limitador nenhum é a postura de segurança inteira desligada em silêncio, exatamente no momento em que um atacante é a explicação mais provável. O que você pode notar enquanto durar: um limite permitindo, por pouco tempo, um pouco mais que o número acima, porque várias instâncias estão contando até ele cada uma. Nada responde diferente, e não há nada para tratar. ORateLimit-Remaining passa a ser o resto daquela instância, e não o da frota
inteira, então ele fica um pouco generoso. Os headers continuam vindo em vez de
desaparecer enquanto isso durar — um contrato que some quando uma dependência
some é um contrato no qual nenhum cliente pode se apoiar.
Ficando abaixo deles
1
Leia os headers na superfície de máquina
O
RateLimit-Remaining da resposta que você já tem é mais barato que um
429. Um job em lote que pausa quando cai abaixo de uma margem nunca
esbarra em nada.2
Faça retry em 429, com backoff
Respeite
Retry-After quando ele vier; use backoff exponencial quando não vier.3
Não faça retry de um 4xx que não seja 429
Um
400 ou um 403 vai responder igual todas as vezes.4
Faça debounce do boot
Um boot por carregamento de página, não um por componente que queira o contato.
5
Limite os seus próprios botões de reenvio
Reenvios de verificação e de magic link são 5 por hora. Um botão sem cooldown
queima isso em segundos e o usuário só vê falha.