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 como 404 Not Found ou 401 Unauthorized não disparam o retry, pois são falhas permanentes do cliente.

  • timeout=5: Parâmetro crítico no requests que impede a execução de ficar travada infinitamente esperando a resposta de um servidor que caiu sem encerrar a conexão.


Comentários

Postagens mais visitadas deste blog

Gerando Relatórios em PDF com Python (ReportLab e FPDF)

Python para Computação Quântica: Introdução com Qiskit

C# e Banco de Dados: Como Conectar e Realizar Operações com SQL Server