5.7 KiB
Proposta — Monitor de sistema (disco, memória, CPU)
Contexto
Quando o servidor cai ou trava, precisamos de visibilidade sobre o estado de disco, memória e CPU nos minutos anteriores à falha — caso contrário o diagnóstico vira adivinhação. O monitor precisa:
- Sobreviver a crash/hang do backend Node (senão não vale nada pós-mortem)
- Ter pouca sobrecarga (não queremos o próprio monitor derrubar o servidor)
- Ser simples de consultar depois do incidente
Opções
🅰 Post-mortem via log rotativo (mínimo viável)
Script bash standalone + systemd timer coletando snapshot a cada 30–60s em
/var/log/newwhats-health.log (rotativo por logrotate).
Campos coletados:
- Uso de disco (
df -h /) - Memória (
free -m— total, usado, livre, cache, swap) - CPU / load average (
uptime,top -bn1 | head) - Processos do newwhats (PID, %CPU, %MEM, comando)
- Rede (
ss -s— conexões TCP ativas) - Uptime (
uptime -p)
Entregáveis:
/opt/newwhats/scripts/collect-health.sh— script bash idempotente/etc/systemd/system/newwhats-health.service— unit oneshot/etc/systemd/system/newwhats-health.timer— timer disparando a cada 30s/etc/logrotate.d/newwhats-health— rotação diária, retenção configurável
Vantagem crítica: roda fora do backend. Sobrevive a crash, hang, OOM
killer, e até a kill -9 do processo Node. Quando o servidor cair, basta
tail /var/log/newwhats-health.log e aparece exatamente o estado nos
últimos minutos.
Desvantagem: sem dashboard — só via terminal.
🅱 Post-mortem + endpoint em tempo real
Tudo do A, mais:
Endpoint /api/admin/system-health no backend que retorna JSON com leitura
ao vivo:
{
uptime: number, // os.uptime()
loadAvg: [n, n, n], // os.loadavg()
memory: {
total: number, // os.totalmem()
free: number, // os.freemem()
usedPct: number,
processRss: number, // process.memoryUsage().rss
processHeap: number, // process.memoryUsage().heapUsed
},
disk: {
total: number, // fs.statfs('/')
free: number,
usedPct: number,
},
cpu: {
cores: number,
model: string,
},
node: {
version: string,
pid: number,
},
}
Protegido por adminMiddleware.
Vantagem: permite montar dashboard no frontend depois sem re-arquitetar. Útil também pra curl/monitoring externo (UptimeRobot, etc).
Desvantagem: endpoint depende do backend estar vivo. Se o processo travou, só o log bash salva. Por isso sempre acompanha o A, nunca substitui.
🅲 A + B + dashboard frontend + alertas
Tudo do B, mais:
- Página admin no frontend (
/admin/system) com gráficos das últimas 24h - Polling do endpoint a cada 5s
- Histórico persistido em tabela Postgres (
system_health_samples) ou stream no Dragonfly (mais leve, TTL de 24h automático) - Emit de
system:alertvia socket.io quando threshold é ultrapassado:- Memória > 90%
- Disco > 85%
- Load >
numCores * 2
- Toast no frontend mostrando o alerta
Desvantagens:
- Adiciona chart lib no frontend (recharts, apex, chart.js — ~50KB gzipped)
- Alertas via socket.io não chegam se o backend estiver morto — falsa sensação de segurança
- Alertas em tempo real geralmente são feitos com ferramenta externa (Grafana/Prometheus/Netdata) — reinventar dentro do app é trabalho sem ROI claro
Recomendação: A+B
Por quê:
- A cobre o caso real que você descreveu ("servidor caiu ou travou"). Post-mortem via log é o que sempre funciona, mesmo no pior cenário.
- B dá um hook pra construir dashboard depois sem refatorar — o
endpoint é pequeno e vive debaixo do
adminMiddleware. - C adiciona complexidade que pode ser feita em sprint futura se você decidir que o ganho vale. Começar sem gráficos é mais barato e mais rápido de entregar.
- Alertas em tempo real são complementares, não substitutos: se você quiser notificações robustas, a resposta é integrar com Prometheus / Grafana / Netdata — que foram feitos pra isso — não reescrever a roda dentro do app.
Decisões que precisam de resposta antes de aplicar
| # | Decisão | Opções | Default sugerido |
|---|---|---|---|
| 1 | Intervalo de coleta | 30s / 60s | 30s (granularidade importa pra detectar spikes) |
| 2 | Retenção do log | 7 dias / 30 dias | 7 dias (rotação diária, arquivo ~10MB/dia) |
| 3 | Notificações imediatas | email / webhook / nada | nada (começar simples) |
| 4 | Path do log | /var/log/newwhats-health.log (precisa root na criação) / /home/deploy/projetos/newwhats.local/logs/health.log (sem sudo) |
/var/log/newwhats-health.log (padrão systemd, integra com logrotate global) |
Escopo explicitamente fora
- ❌ Monitoramento distribuído (vários hosts)
- ❌ Alertas por SMS/WhatsApp/Slack
- ❌ Dashboard com gráficos históricos (fica na Opção C)
- ❌ Integração com Prometheus/Grafana/Netdata (trabalho separado, fora do scope do app)
- ❌ APM / tracing de requests (é outra categoria de ferramenta)
- ❌ Monitor de health do Postgres / Dragonfly (checar separadamente se houver sintomas — hoje não é gargalo)
Estimativa de entrega (referência, não commitment)
Opção A isolada: script bash + 2 units systemd + logrotate config → 3 arquivos pequenos, baixa superfície.
Opção A+B: adiciona 1 endpoint no backend (~40 linhas TypeScript) e
uma chamada em server.ts pra montar a rota. Sem mudança no frontend.
Opção C: soma uma página React com gráficos + migration + lógica de sample + lógica de alerta + toast handler. Bem mais trabalho.