O Retry-After cabeçalho: quanto tempo esperar antes de tentar novamente

Retry-After é um cabeçalho de resposta HTTP que indica à sua aplicação quanto tempo deve esperar antes de enviar o próximo pedido. O valor é ou um número de segundos ou uma data HTTP. Quando uma API o envia, é a resposta mais fiável para "quando podes tentar novamente?" porque vem do servidor que recusou o teu pedido. Para mais informações, consulte o RFC 9110, secção 10.2.3.

Como é Retry-After

O cabeçalho tem 2 formatos. A tua aplicação tem de tratar de ambos.

Format Example O que significa
Seconds Retry-After: 120 Aguarda 120 segundos (2 minutos) desde que recebeste a resposta. O valor é um número inteiro não negativo.
data HTTP Retry-After: Fri, 31 Dec 1999 23:59:59 GMT Não envie o pedido novamente antes desta altura. A data está sempre em GMT.

Os servidores enviam Retry-After com estes códigos de estado:

Status O que Retry-After significa Source
429 Too Many Requests Quanto tempo esperar antes de enviar um novo pedido? O servidor pode incluí-lo. RFC 6585, secção 4
503 Service Unavailable Quanto tempo se espera que o serviço esteja indisponível. O servidor pode incluí-lo. RFC 9110, secção 15.6.4
413 Content Too Large Se a condição for temporária, o servidor deve informar depois de quanto tempo deixará de se verificar. RFC 9110, secção 15.5.14
Qualquer 3xx redirecionamento O tempo mínimo para esperar antes de seguir o redirecionamento. RFC 9110, secção 10.2.3

O cabeçalho é opcional. Algumas APIs usam os seus próprios cabeçalhos. Por exemplo, o GitHub indica-te através de x-ratelimit-reset quando o teu limite é reiniciado. Para mais informações, veja Limite de pedidos da API do GitHub excedido.

Como lidar com Retry-After

  1. Leia ambos os formatos. Se o valor for um número, é em segundos. Caso contrário, analise-o como uma data e subtraia a hora atual. Se a data já tiver passado, pode tentar novamente imediatamente.
  2. Espere pelo menos o tempo que o cabeçalho indicar. Tentar novamente mais cedo normalmente resulta em outro 429 ou 503. Algumas APIs continuam a contar os teus pedidos enquanto aplicam limitação de taxa, por isso tentativas antecipadas podem aumentar o tempo de espera. Por exemplo, veja as orientações do Microsoft Graph para limitação (throttling).
  3. Recorrer a backoff com jitter quando o cabeçalho estiver em falta. Duplique o tempo de espera após cada tentativa falhada, adicione um valor aleatório para que muitos clientes não voltem a tentar no mesmo momento e defina um limite máximo para esse tempo de espera.
  4. Limita as tuas tentativas. Após algumas tentativas, devolve o erro ao chamador.
  5. Verifica se uma nova tentativa pode ajudar. Algumas APIs retornam 429 quando os seus créditos se esgotam ou atinge o limite de despesa. Esperar não resolve essas coisas. Para um exemplo, veja OpenAI insufficient_quota e credit_balance_exhausted.
function retryDelayMs(response, attempt) {
  const value = response.headers.get('retry-after');
  if (value) {
    const seconds = Number(value);
    const ms = Number.isNaN(seconds) ? Date.parse(value) - Date.now() : seconds * 1000;
    if (!Number.isNaN(ms)) {
      return Math.max(ms, 0);
    }
  }
  // No usable header: exponential backoff with jitter, capped at 30 seconds
  return Math.random() * Math.min(30_000, 1_000 * 2 ** attempt);
}

Muitos SDKs tratam de Retry-After por si, mas só até ficarem sem tentativas. Então o teu código gera o erro.

SDK O que faz por defeito
.NET manipulador de resiliência padrão Tenta novamente as respostas 408, 429 e 5xx até 3 vezes com backoff exponencial e jitter. Usa Retry-After para o atraso porque ShouldRetryAfterHeader por defeito é true.
Microsoft Graph SDKs Usa Retry-After quando está presente, e recorre ao backoff exponencial quando não está. Os pedidos dentro de um lote JSON não são retentados automaticamente.
OpenAI Python SDK Tenta novamente em caso de erros de ligação e as respostas 408, 409, 429 e 5xx 2 vezes com um curto backoff exponencial. Configure max_retries para o alterar.

Verifica a documentação do teu SDK para a política exata e testa o que acontece depois da última tentativa falhar.

Como testar se a sua aplicação lida com Retry-After

Raramente obténs um Retry-After enquanto desenvolves, e quando o obténs, não consegues controlar o seu valor. Por isso, a forma como testas isto decide se encontras os bugs antes dos teus utilizadores.

Approach O que encontra Do que sentes falta
Aguardar o ambiente de produção Fracassos reais Tudo, até que um utilizador lhe clique
Simula a API nos teus testes, ou deixa o teu agente de programação escrever o mock Se o seu código analisa o cabeçalho Se o teu cliente HTTP real ou o SDK aguardam tempo suficiente, e o que a API realmente envia. A tua aplicação também precisa de um switch só de teste para chegar ao mock.
Faz pedidos à API real até que te limite Comportamento real Não podes ativar uma resposta com limitação de taxa a pedido, e acabas por gastar a tua quota real
Intercete o tráfego real da sua aplicação e devolva respostas com limitação de taxa a pedido Se o teu SDK real e a política de repetição esperam o tempo que o cabeçalho indicar Nada na tua aplicação muda, por isso não testa o teu código isoladamente. Guarda os testes unitários para isso.

Experimente na sua app

O Dev Proxy interceta os pedidos da sua aplicação às APIs que escolhe e devolve 429 as respostas com um cabeçalho Retry-After, enquanto a sua aplicação continua a chamar os URLs reais. O RetryAfterPlugin lembra-se de quando cada pedido sujeito a limitação de taxa pode ser tentado novamente. Se a sua aplicação chamar o mesmo URL antes desse momento, o Dev Proxy reporta e limita novamente o pedido. O plugin regista apenas respostas 429.

No teu ficheiro de erros para o GenericRandomErrorPlugin, define o Retry-After valor de uma 429 resposta para @dynamic, e o Dev Proxy preenche o número de segundos e regista-o por ti.

Para experimentar, descarregue um preset que use ambos os plugins e inicie o Dev Proxy com ele:

devproxy config get openai-throttling
devproxy --config-file "~dataFolder/configs/openai-throttling/.devproxy/devproxyrc.json"

Depois executa a tua aplicação como de costume e vê o que faz. Para instalar Dev Proxy, consulte Configurar Dev Proxy.

Passos seguintes

Ver também