Resiliência e Fallbacks¶
O agrobr foi projetado para ser robusto e resiliente a falhas. Este documento explica as camadas de defesa implementadas.
Camadas de Defesa¶
┌─────────────────────────────────────────────────────────────────┐
│ CAMADAS DE DEFESA - AGROBR │
├─────────────────────────────────────────────────────────────────┤
│ │
│ CAMADA 1: PREVENÇÃO │
│ ├─ Structure Monitor (6h) → Detecta mudanças antecipadas │
│ ├─ Golden Data Tests (CI) → Garante parsing não regride │
│ └─ Fingerprint Baseline → Referência para comparação │
│ │
│ CAMADA 2: DETECÇÃO │
│ ├─ Fingerprint Check → HTML estruturalmente diferente?│
│ ├─ can_parse() Confidence → Parser reconhece estrutura? │
│ └─ User-Agent Rotation → Evita bloqueio de IP │
│ │
│ CAMADA 3: VALIDAÇÃO │
│ ├─ Pydantic Validation → Tipos e formatos corretos? │
│ ├─ Sanity Check → Valores dentro do range? │
│ └─ Completeness Check → Dados parciais (< 80%)? │
│ │
│ CAMADA 4: FALLBACK │
│ ├─ Parser Cascade → Tenta próximo parser │
│ ├─ Cache Fallback → Retorna cache stale │
│ ├─ History Fallback → Busca histórico permanente │
│ └─ Source Fallback → Fonte alternativa (NA) │
│ │
│ CAMADA 5: ALERTAS │
│ ├─ Multi-canal → Slack, Discord, Email │
│ ├─ GitHub Issue → Tracking automático │
│ └─ Logging Estruturado → Debug facilitado │
│ │
└─────────────────────────────────────────────────────────────────┘
Retry com Exponential Backoff¶
Todas as requisições HTTP usam retry automático:
# Configuração padrão
max_retries = 3
base_delay = 1.0 # segundos
max_delay = 30.0 # segundos
exponential_base = 2
# Delays: 1s → 2s → 4s (máx 30s)
Status codes que acionam retry: - 408 Request Timeout - 429 Too Many Requests - 500 Internal Server Error - 502 Bad Gateway - 503 Service Unavailable - 504 Gateway Timeout
Rate Limiting¶
Cada fonte tem seu próprio rate limit, configurável via env vars:
| Fonte | Intervalo | Env var |
|---|---|---|
| ABIOVE | 3 segundos | AGROBR_HTTP_RATE_LIMIT_ABIOVE |
| ANDA | 3 segundos | AGROBR_HTTP_RATE_LIMIT_ANDA |
| BCB | 1 segundo | AGROBR_HTTP_RATE_LIMIT_BCB |
| CEPEA | 2 segundos | AGROBR_HTTP_RATE_LIMIT_CEPEA |
| ComexStat | 2 segundos | AGROBR_HTTP_RATE_LIMIT_COMEXSTAT |
| CONAB | 3 segundos | AGROBR_HTTP_RATE_LIMIT_CONAB |
| DERAL | 3 segundos | AGROBR_HTTP_RATE_LIMIT_DERAL |
| IBGE | 1 segundo | AGROBR_HTTP_RATE_LIMIT_IBGE |
| IMEA | 1 segundo | AGROBR_HTTP_RATE_LIMIT_IMEA |
| INMET | 0.5 segundo | AGROBR_HTTP_RATE_LIMIT_INMET |
| NASA POWER | 1 segundo | AGROBR_HTTP_RATE_LIMIT_NASA_POWER |
| Notícias Agrícolas | 2 segundos | AGROBR_HTTP_RATE_LIMIT_NOTICIAS_AGRICOLAS |
| USDA | 1 segundo | AGROBR_HTTP_RATE_LIMIT_USDA |
| Default | 1 segundo | AGROBR_HTTP_RATE_LIMIT_DEFAULT |
O rate limiter usa semáforos por fonte, permitindo requests paralelos a fontes diferentes.
Configuração HTTP Centralizada¶
Todos os clients usam HTTPSettings (env prefix AGROBR_HTTP_):
# Timeouts (segundos)
export AGROBR_HTTP_TIMEOUT_CONNECT=10
export AGROBR_HTTP_TIMEOUT_READ=30
export AGROBR_HTTP_TIMEOUT_WRITE=10
export AGROBR_HTTP_TIMEOUT_POOL=10
# Retry
export AGROBR_HTTP_MAX_RETRIES=3
export AGROBR_HTTP_RETRY_BASE_DELAY=1.0
export AGROBR_HTTP_RETRY_MAX_DELAY=30.0
Via código:
from agrobr.http import get_timeout, get_rate_limit, get_client_kwargs
from agrobr.constants import Fonte
timeout = get_timeout() # httpx.Timeout
rate = get_rate_limit(Fonte.CEPEA) # 2.0
kwargs = get_client_kwargs(Fonte.CEPEA) # dict para httpx.AsyncClient(**kwargs)
User-Agent Rotativo¶
Pool de User-Agents reais e atuais:
- Chrome Windows (múltiplas versões)
- Chrome Mac
- Firefox Windows/Mac
- Edge
- Safari
Rotação determinística por fonte para parecer tráfego natural.
Fallback de Encoding¶
Chain de fallback para encoding:
- UTF-8 (padrão)
- ISO-8859-1 (Latin-1, comum em sites BR antigos)
- Windows-1252 (CP1252, padrão Excel BR)
- UTF-16 (raro)
- Detecção automática (chardet)
- UTF-8 com replacement (último recurso)
Fallback de Fonte¶
CEPEA¶
CEPEA (www.cepea.org.br)
↓ bloqueado (Cloudflare)?
Notícias Agrícolas (httpx direto, SSR)
↓ soft block (consent/challenge page)?
↓ falhou (HTTP error)?
Cache local (DuckDB)
O Notícias Agrícolas republica os mesmos indicadores CEPEA/ESALQ via HTML server-side rendered, sem necessidade de Playwright.
Cada etapa retorna um FetchResult(html, source) que identifica explicitamente a origem do HTML ("cepea", "browser" ou "noticias_agricolas"), evitando detecção frágil por markers no conteúdo.
Soft block detection: Alguns usuários recebem do NA uma página de consent/challenge (HTTP 200, ~10KB sem tabela) em vez da página de dados (~75KB com tabela). O client NA valida o conteúdo antes de retornar: se o HTML é < 20KB e não contém <table, levanta SourceUnavailableError, ativando o cache fallback.
Cache e Histórico¶
Cache Volátil¶
- TTL configurável por fonte
- Usado para respostas rápidas
- Expira automaticamente
Histórico Permanente¶
- Nunca expira
- Acumula dados progressivamente
- Permite reconstruir séries históricas
- Útil em modo offline
Fluxo de Cache¶
Request
│
▼
Cache fresh? ──yes──→ Retorna cache
│no
▼
Fetch fonte
│
├─success──→ Atualiza cache + histórico
│
└─fail──→ Cache stale? ──yes──→ Retorna stale + warning
│no
▼
Histórico? ──yes──→ Retorna histórico + warning
│no
▼
SourceUnavailableError
Fingerprinting de Layout¶
Detecta mudanças de layout antes que causem erros:
Componentes da fingerprint: - Classes CSS das tabelas - IDs relevantes (preço, indicador, etc.) - Headers de tabelas - Contagem de elementos estruturais - Hash da hierarquia de tags
Thresholds:
| Similaridade | Ação |
|---|---|
| > 85% | OK, parsing normal |
| 70-85% | Warning, tenta parsing |
| < 70% | Erro, layout mudou muito |
Validação Estatística¶
Sanity checks baseados em ranges históricos:
# Exemplo: Soja
min_value = 30 # R$/sc (mínimo histórico ~R$40)
max_value = 300 # R$/sc (máximo histórico ~R$200)
max_daily_change = 15% # Variação diária máxima
Anomalias são marcadas nos dados mas não bloqueiam retorno (soft validation).
Health Checks¶
Verificações automáticas:
- Conectividade: HTTP GET responde?
- Latência: < 5 segundos?
- Parsing: Parser extrai dados?
- Fingerprint: Estrutura similar ao baseline?
GitHub Actions¶
- Daily Health Check: 2x ao dia (9h e 21h BRT)
- Structure Monitor: A cada 6 horas
- Tests: Em cada PR
Alertas¶
Canais Suportados¶
# Slack
export AGROBR_ALERT_SLACK_WEBHOOK=https://hooks.slack.com/...
# Discord
export AGROBR_ALERT_DISCORD_WEBHOOK=https://discord.com/api/webhooks/...
# Email (SendGrid)
export AGROBR_ALERT_SENDGRID_API_KEY=SG...
export AGROBR_ALERT_EMAIL_TO=["admin@example.com"]
Níveis de Alerta¶
| Nível | Trigger | Canais |
|---|---|---|
| Info | Health check OK | Logs apenas |
| Warning | Fingerprint drift, cache stale | Slack/Discord |
| Critical | Parse failed, fonte down | Todos + GitHub Issue |
Modo Offline¶
Para trabalhar sem conexão:
# Via código
df = await cepea.indicador('soja', offline=True)
# Via ambiente
export AGROBR_CACHE_OFFLINE_MODE=true
Usa apenas cache e histórico local.
Telemetria (Opt-in)¶
Coleta anônima para melhorar o pacote:
O que é coletado: - Fontes mais usadas - Produtos mais consultados - Taxa de cache hit/miss - Erros de parsing (tipo, frequência) - Latência de requests
Nunca coletamos: - IPs ou dados pessoais - Conteúdo dos dados - Informações identificáveis
Comando Doctor¶
Use o comando doctor para diagnosticar saúde do sistema:
Exemplo de saída¶
agrobr diagnostics v0.6.3
==================================================
Sources Connectivity
[OK] CEPEA (Noticias Agricolas) 142ms
[OK] CONAB 89ms
[OK] IBGE/SIDRA 67ms
Cache Status
Location: ~/.agrobr/cache/agrobr.duckdb
Size: 2.40 MB
Total records: 1,247
By source:
CEPEA: 847 records (2025-01-21 to 2026-02-04)
CONAB: 305 records (2024-01-01 to 2026-02-04)
IBGE: 95 records (2020-01-01 to 2023-12-31)
Cache Expiry
CEPEA: Expira as 18h (atualizacao CEPEA)
CONAB: TTL 24 horas
IBGE: TTL 7 dias
Configuration
Alternative source: enabled (Notícias Agrícolas via httpx)
[OK] All systems operational
Output JSON¶
Para integração com sistemas de monitoramento:
Verbose¶
Para informações detalhadas: