Pular para conteúdo

RUNBOOK — QuantFX (ML-Forex)

Objetivo: ter procedimentos passo-a-passo para os 8 cenários de falha mais prováveis. Se você ou alguém de confiança seguir o que está aqui, qualquer um deve voltar em ≤1 hora sem precisar improvisar.

Princípio: primeiro estanca o sangramento (recuperar serviço), depois investiga (logs/causa-raiz), por último corrige permanente.


🗺️ Mapa rápido — onde está o quê

Coisa Lugar
API (FastAPI) VPS 177.7.58.99 — container forex_api em /opt/quantfx/
Worker (predict/retrain) PC local H: — container forex_worker em C:/Users/henri/Documents/PROJETOS/ML-Forex/
Database (Postgres 16) VPS — container forex_db, db forex, user forex
Cache (Redis) VPS — container forex_redis
Backups Backblaze B2 bucket quantfx-backups-prod (cluster us-east-005)
Domínio quantfx.com.br + api.quantfx.com.br (Cloudflare)
Monitoração UptimeRobot — https://dashboard.uptimerobot.com/monitors
Frontend Servido pela própria API (rotas /, /dashboard, /planos, etc.)

SSH VPS: ssh root@177.7.58.99 (chave em C:/Users/henri/.ssh/id_ed25519)


🚑 Cenário 1 — API caiu (UptimeRobot vermelho, EAs não recebem sinal)

Sintomas: Email/SMS do UptimeRobot. curl https://api.quantfx.com.br/api/health retorna 502, timeout ou 5xx.

1.1 Diagnóstico (30 segundos)

ssh root@177.7.58.99 "docker ps --format 'table {{.Names}}\t{{.Status}}'"

Decisão: - forex_api não aparece ou Exitedvai pra 1.2 (restart) - forex_api está Up mas health falha → vai pra 1.3 (deep check) - Tudo Up mas não acessível externamente → vai pra 1.4 (rede/CF)

1.2 Restart simples

ssh root@177.7.58.99 "cd /opt/quantfx && docker compose -f docker-compose.vps.yml up -d api"
sleep 10
curl -s -w "\n%{http_code}\n" https://api.quantfx.com.br/api/health
Se voltar 200 + status:ok → resolvido. Investigue logs depois com:
ssh root@177.7.58.99 "docker logs forex_api --tail 200"

1.3 Deep check (container Up mas /health falha)

ssh root@177.7.58.99 "docker logs forex_api --tail 100" | grep -iE "error|traceback|fatal|critical"
ssh root@177.7.58.99 "docker exec forex_api curl -s http://localhost:8000/api/health"

Causas comuns: - DB indisponível: docker logs forex_db | tail -50 — se DB caiu, restart: docker start forex_db && sleep 10 && docker restart forex_api - Bug em deploy recente: rollback do container — docker compose -f docker-compose.vps.yml pull api (se imagem versionada) ou restore do código via scp da última versão conhecida boa - OOM (memória estourada): dmesg | tail -30 mostra OOM kill — aumentar swap ou matar grafana temporariamente

1.4 Container Up mas inacessível externamente

  • Verifica Cloudflare: https://www.cloudflarestatus.com
  • Verifica DNS: dig api.quantfx.com.br
  • Verifica firewall: ssh root@177.7.58.99 "ufw status" — porta 80/443 abertas?

🤖 Cenário 2 — Worker travou (sem predição há > 15 min)

Sintomas: UptimeRobot marca /api/health como degraded (503 com status:"degraded"). pred_lag_minutes > 30. Alerta Telegram de cobertura.

2.1 Diagnóstico

No PC local (worker roda aqui, não na VPS):

docker ps --filter name=forex_worker --format "table {{.Names}}\t{{.Status}}"
docker logs forex_worker --tail 50

Verifica heartbeat (atualizado a cada ciclo):

docker exec forex_worker stat /tmp/worker_heartbeat
Se o Modify: for > 5 min atrás, worker travou.

2.2 Restart

cd C:\Users\henri\Documents\PROJETOS\ML-Forex
docker compose restart worker

⚠️ Se mudou código Python, restart não basta — precisa rebuild:

docker compose up -d --build worker

2.3 Worker repetidamente cai

Provável bug em alguma feature/modelo. Plano:

docker logs forex_worker --tail 200 | findstr /R "Traceback Error"
Se for crash em treinamento, desabilita temporariamente o retrain comentando maybe_retrain() em scripts/run_worker.py linha ~1898, rebuild, e investiga depois com cabeça fria.


🔇 Cenário 3 — Sinais zerados (alerta "0 sinais em 24h")

Sintomas: Mensagem Telegram 🔇 Silêncio anômalo. Sistema rodando mas todas as predições são NO_TRADE.

3.1 Diagnóstico

ssh root@177.7.58.99 "docker exec forex_db psql -U forex -d forex -c \"
SELECT signal, COUNT(*) FROM predictions
WHERE created_at >= NOW() - INTERVAL '24 hours'
GROUP BY signal;\""

3.2 Checar feature integrity (foi o que pegou o bug FDA)

ssh root@177.7.58.99 "docker exec forex_db psql -U forex -d forex -c \"
SELECT s.symbol, t.tf_code, f.payload->'fda_close' as fda_close, f.ts
FROM features f
JOIN symbols s USING(symbol_id)
JOIN timeframes t USING(tf_id)
WHERE f.ts >= NOW() - INTERVAL '1 hour'
ORDER BY f.ts DESC LIMIT 10;\""
Se fda_close é NULL, é o mesmo bug que tivemos → feature não está sendo computada. Investigue app/features/build_features.py.

3.3 Causas possíveis (em ordem de probabilidade)

  1. Conformal gate travado (calibradores desatualizados após mudança de features) → trigger retrain
  2. Threshold muito alto → checar configs/model.yaml decision.tau e validar limiar relativo em app/models/predict.py
  3. Auto-rollback ativou em todos os slots → checar ls -la models/.bias_rollback_state.json
  4. Feature ausente em produção → vide 3.2

3.4 Recurso de emergência — forçar threshold mais baixo

Não recomendado, mas se precisar gerar sinais rapidamente (ex: demonstração ao vivo): - Editar configs/model.yamldecision.tau: 0.550.50 - Rebuild worker - Reverte no dia seguinte — esses sinais não passaram pelos gates de qualidade


🗄️ Cenário 4 — DB inacessível

Sintomas: /api/health retorna status:"down","db":"error". Logs API cheios de connection refused.

4.1 Diagnóstico

ssh root@177.7.58.99 "docker ps -a --filter name=forex_db"
ssh root@177.7.58.99 "docker logs forex_db --tail 50"

4.2 Restart simples

ssh root@177.7.58.99 "docker start forex_db && sleep 15 && docker restart forex_api"

4.3 DB não sobe (corruption)

ssh root@177.7.58.99 "docker logs forex_db 2>&1 | tail -100"
Se vir database system is shut down, PANIC, ou corruption, fazer restore:
# No PC local
cd C:\Users\henri\Documents\PROJETOS\ML-Forex
.venv\Scripts\python.exe scripts\restore_from_b2.py --list
# Pegar a data do backup mais recente, ex: 20260522
.venv\Scripts\python.exe scripts\restore_from_b2.py --restore-db 20260522
# Inspeciona no DB temporário forex_restore antes de comitar
docker exec forex_db psql -U forex -d forex_restore -c "SELECT COUNT(*) FROM predictions;"
# Se OK, restaura sobre o de produção (CUIDADO):
.venv\Scripts\python.exe scripts\restore_from_b2.py --restore-db-prod 20260522 --confirm
RTO: ~30 min. Perda de dados: até 24h (backup é diário 03:00 BRT).


💾 Cenário 5 — Disco cheio na VPS

Sintomas: API começa a falhar, logs com No space left on device.

5.1 Diagnóstico

ssh root@177.7.58.99 "df -h / && du -sh /var/lib/docker/* | sort -rh | head -10"

5.2 Limpeza imediata (libera 5-20 GB)

ssh root@177.7.58.99 "docker system prune -af --volumes"   # CUIDADO: remove volumes não-usados
ssh root@177.7.58.99 "find /opt/quantfx -name '*.log' -size +100M -delete"

5.3 Reduzir crescimento futuro

  • DB tem retention de 90 dias em predictions (já configurado em maybe_cleanup_db)
  • Logs do Docker: configurar max-size: 10m em /etc/docker/daemon.json (não está):
    {"log-driver":"json-file","log-opts":{"max-size":"10m","max-file":"3"}}
    
    Reinicia Docker: systemctl restart docker (CUIDA: derruba tudo).

🔐 Cenário 6 — Key suspeita (compartilhada/vazada)

Sintomas: Alerta de rate limit por IP (mesma key em > 3 IPs simultâneos). Comportamento anômalo.

6.1 Diagnóstico

# Quais keys e seus heartbeats
ssh root@177.7.58.99 "docker exec forex_db psql -U forex -d forex -c \"
SELECT user_name, plan_tier, last_seen_at,
       EXTRACT(EPOCH FROM (NOW() - last_seen_at))/60 as min_since
FROM api_keys WHERE active=TRUE
ORDER BY last_seen_at DESC;\""

6.2 Revogar key suspeita

# Via endpoint admin
curl -X DELETE "https://api.quantfx.com.br/admin/keys/<key_id>" \
  -H "X-Admin-Secret: $ADMIN_SECRET"

# Ou direto no DB
ssh root@177.7.58.99 "docker exec forex_db psql -U forex -d forex -c \"
UPDATE api_keys SET active=FALSE WHERE key_id=123;\""
Imediatamente entra em contato com o usuário (email/whats) — informa que detectou uso de múltiplos IPs e está revogando por segurança. Emite nova key se ele justificar (ex: VPS dele + PC).


📉 Cenário 7 — Modelo gerando sinais ruins (Sharpe/PF despencando)

Sintomas: Alerta Telegram 🟡 Degradação detectada (CUSUM). Performance < threshold no /api/performance.

7.1 Auto-rollback já tentou?

ssh root@177.7.58.99 "docker exec forex_db psql -U forex -d forex -c \"
SELECT * FROM model_versions
WHERE rolled_back_at IS NOT NULL
AND rolled_back_at > NOW() - INTERVAL '7 days';\""
Se sim, o rollback automático já agiu. Não toque. Inspecione modelo restaurado e investigue treino com cabeça fria depois.

7.2 Rollback manual (se auto-rollback não disparou)

# PC local
cd C:\Users\henri\Documents\PROJETOS\ML-Forex
# Lista modelos disponíveis no histórico do B2
.venv\Scripts\python.exe scripts\restore_from_b2.py --list-models EURUSD H1
# Restaurar versão específica
.venv\Scripts\python.exe scripts\restore_from_b2.py --restore-model EURUSD H1 20260501
docker compose up -d --build worker

7.3 Desativar slot problemático temporariamente

Marca o slot como inativo no DB para parar de gerar predições:

UPDATE symbols SET is_active=FALSE WHERE symbol='XXXX';
Comunica nos canais (Telegram/Discord) que XXXX está temporariamente off para investigação.


☁️ Cenário 8 — Cloudflare bloqueando ou DNS quebrado

Sintomas: Site fora externamente mas containers Up. curl direto IP funciona, curl domain não.

8.1 Diagnóstico

dig api.quantfx.com.br +short                       # Deve mostrar IP CF
curl --resolve api.quantfx.com.br:443:<CF_IP> ...   # Bypass DNS
ssh root@177.7.58.99 "curl -s http://localhost:8000/api/health"   # Direto sem CF

8.2 Bypass Cloudflare emergencial

  • Loga no Cloudflare dashboard → DNS → mudar o registro de Proxied (laranja) para DNS only (cinza)
  • DNS propaga em ~1 min. UptimeRobot e EAs voltam a alcançar direto.
  • Lembre de religar o proxy depois (Cloudflare oferece DDoS, cache, certificado).

8.3 SSL/cert expirado

Cloudflare gerencia. Verificar em Cloudflare dashboard → SSL/TLS → Edge Certificates → status.


🆘 Cenário 9 — "Não sei o que está errado" (último recurso)

Sintomas confusos ou múltiplas coisas pifando. Restart completo da pilha:

# Worker
docker compose restart worker

# API + DB + Redis (na VPS)
ssh root@177.7.58.99 "cd /opt/quantfx && docker compose -f docker-compose.vps.yml restart"
sleep 30
curl https://api.quantfx.com.br/api/health

Se ainda quebrado: leia logs na ordem e procure o primeiro ERROR/Traceback cronológico:

ssh root@177.7.58.99 "docker logs forex_db --since 1h --tail 50"
ssh root@177.7.58.99 "docker logs forex_api --since 1h --tail 100"
docker logs forex_worker --since 1h --tail 100


📞 Quem chamar (escalonamento)

Camada Quem Quando
1. Você Henrique Sempre primeiro
2. Hosting Hostinger suporte Se VPS não pingar (problema do datacenter)
3. Cloudflare https://www.cloudflarestatus.com Se DNS/proxy estiver fora globalmente
4. Backblaze https://status.backblaze.com Se restore B2 falhar

✅ Pós-incident (sempre depois)

  1. Documenta no Telegram/notes: o quê + quando + o quê causou + o que resolveu
  2. Atualiza este runbook com aprendizado novo
  3. Avisa os assinantes se eles foram impactados (transparência > drama)
  4. Cria task de causa-raiz para que isso não volte