Tratamento de Falhas em APIs com Python: Implementando Retry no Requests
Tratamento de Falhas em APIs com Python: Implementando Retry no Requests
Ao consumir APIs externas, é comum enfrentar falhas temporárias de conexão, erros de limite de requisições (rate limit) ou instabilidades no servidor (erros HTTP 500, 502, 503, 504). Implementar um mecanismo de Retry com Exponential Backoff faz com que o script tente realizar a requisição novamente com intervalos de tempo crescentes, aumentando a resiliência da aplicação sem sobrecarregar a API.
Instalação da Biblioteca
Bash
pip install requests
1. Método Nativo com urllib3 e Requests (Recomendado)
O próprio módulo
urllib3 (utilizado internamente pelo requests) possui uma classe chamada Retry que gerencia as tentativas de reconexão e o cálculo do tempo de espera automaticamente.Python
import requests
from urllib3.util import Retry
from requests.adapters import HTTPAdapter
def criar_sessao_com_retry(
retries_totais=3,
fator_backoff=1,
status_para_tentar=[429, 500, 502, 503, 504]
):
sessao = requests.Session()
# Configura a estratégia de tentativas e tempos de espera
estrategia_retry = Retry(
total=retries_totais,
backoff_factor=fator_backoff,
status_forcelist=status_para_tentar,
allowed_methods=["GET", "POST", "PUT", "DELETE"]
)
# Aplica a estratégia aos protocolos HTTP e HTTPS
adaptador = HTTPAdapter(max_retries=estrategia_retry)
sessao.mount("http://", adaptador)
sessao.mount("https://", adaptador)
return sessao
# Exemplo de uso:
url_api = "https://jsonplaceholder.typicode.com/posts/1"
http = criar_sessao_com_retry(retries_totais=4, fator_backoff=2)
try:
resposta = http.get(url_api, timeout=5)
resposta.raise_for_status()
dados = resposta.json()
print("✅ Dados recebidos com sucesso:", dados["title"])
except requests.exceptions.RequestException as erro:
print(f"❌ Falha definitiva na requisição após tentativas: {erro}")
2. Método Customizado com Loop e time.sleep (Sem Dependências Adicionais)
Caso queira entender a lógica do cálculo do tempo do backoff exponencial ou aplicar em scripts simples sem acoplar à classe de sessão:
Python
import time
import requests
def requisicao_com_backoff(url, max_tentativas=3, backoff_inicial=1):
for tentativa in range(1, max_tentativas + 1):
try:
resposta = requests.get(url, timeout=5)
resposta.raise_for_status()
return resposta.json()
except (requests.exceptions.RequestException, requests.exceptions.HTTPError) as erro:
# Se atingiu a última tentativa, lança a exceção
if tentativa == max_tentativas:
print(f"❌ Tentativa {tentativa}/{max_tentativas} falhou. Limite atingido.")
raise erro
# Cálculo do tempo de espera exponencial: 1s, 2s, 4s, 8s...
tempo_espera = backoff_inicial * (2 ** (tentativa - 1))
print(f"⚠️ Falha na tentativa {tentativa}. Aguardando {tempo_espera}s antes de tentar novamente...")
time.sleep(tempo_espera)
# Exemplo de uso:
try:
dados = requisicao_com_backoff("https://httpbin.org/status/503", max_tentativas=3)
except Exception as e:
print("Processo finalizado com erro capturado.")
Pontos-Chave
- fator_backoff (Exponential Backoff): Define a escala do tempo de pausa entre falhas. Com um fator de
1, o tempo de espera segue a progressão: $1s$, $2s$, $4s$, $8s \dots$ - status_forcelist (
[429, 500, 502, 503, 504]): Garante que o script só repita a requisição se o erro for temporário (ex: indisponibilidade de servidor ou limite de requisições excedido). Erros como404 Not Foundou401 Unauthorizednão disparam o retry, pois são falhas permanentes do cliente. - timeout=5: Parâmetro crítico no
requestsque impede a execução de ficar travada infinitamente esperando a resposta de um servidor que caiu sem encerrar a conexão.

Comentários
Postar um comentário