Microserviço que expõe, via um único endpoint REST, o uso de CPU e RAM da máquina e a conectividade de rede (latência de ping e status de portas essenciais).
Status: protótipo funcional — coleta de métricas de sistema e rede funcionando e containerizado; sem autenticação, persistência ou testes implementados ainda.
Uma equipe de TI que quer saber rapidamente "esse servidor está saudável?" normalmente precisa entrar na máquina e rodar vários comandos separados: top pra CPU, free pra RAM, ping pra latência, telnet/nc pra ver se uma porta está aberta.
Este microserviço junta essas checagens atrás de uma única chamada HTTP. Um GET /metrics devolve tudo de uma vez, num JSON só, pronto pra ser consumido por qualquer painel ou script de monitoramento.
flowchart TD
A[GET /metrics] --> B[Coleta uso de CPU - psutil, bloqueia 1s]
B --> C[Coleta uso de RAM - psutil]
C --> D[Ping para google.com - ate 2s]
D --> E[Verifica porta 80 - HTTP]
E --> F[Verifica porta 22 - SSH]
F --> G[Retorna JSON com metricas de sistema e rede]
Cada chamada ao endpoint dispara as cinco coletas em sequência, uma depois da outra, e só devolve a resposta quando todas terminam.
app/main.py— define o único endpoint,GET /metrics, e orquestra as chamadas aos dois módulos de coleta. Não tem lógica própria além de montar o JSON de resposta.app/core/metrics.py— coleta uso de CPU e RAM do host viapsutil.app/core/network.py— verifica latência (ping) e se portas TCP específicas estão abertas.app/models/schemas.py— arquivo criado, reservado para os modelos Pydantic da resposta; hoje está vazio, e/metricsdevolve um dicionário Python puro, sem validação de schema de saída.app/tests/test_metrics.py— arquivo de teste criado, ainda sem casos implementados.
Endpoint único (/metrics) — comecei simples, com uma rota que devolve tudo de uma vez, pra não precisar desenhar uma API mais rica antes de validar se as métricas certas estavam sendo coletadas corretamente.
psutil para CPU/RAM — é a biblioteca padrão de fato pra esse tipo de coleta em Python; evita ter que ler /proc na mão e lidar com diferenças entre sistemas operacionais.
pythonping em vez de chamar o ping do sistema via subprocess — preferi uma lib Python nativa a depender do binário ping do SO, que tem flags diferentes entre Linux, Windows e macOS.
Socket cru pra checar porta, em vez de uma lib de scan — só precisava saber "abriu ou não abriu"; um socket TCP com timeout curto resolve isso sem trazer uma dependência maior.
Timeouts curtos (2s no ping, 1s no socket) — decisão consciente pra a checagem nunca ficar pendurada esperando uma rede lenta ou um host fora do ar.
Docker desde o início — pensando em rodar isso em qualquer ambiente de CI ou orquestrador sem depender de ter Python instalado na máquina.
Rota async chamando funções síncronas e bloqueantes. get_all_metrics é async def, mas as cinco coletas internas (psutil.cpu_percent, ping, dois check_port) são todas síncronas. O próprio psutil.cpu_percent(interval=1) já impõe 1 segundo de bloqueio no event loop por chamada — é o piso de latência do endpoint, não uma exceção. No pior caso, somando o timeout do ping e das duas portas, uma única requisição pode travar o event loop inteiro por vários segundos, e uma segunda requisição simultânea espera a primeira terminar tudo antes de começar. Funciona bem pra uma consulta manual ocasional; não escalaria com clientes fazendo polling frequente.
Alvo de rede fixo em google.com. Prova que a conectividade externa da máquina funciona, mas não monitora nenhum servidor real da infraestrutura de quem usa o serviço — isso ainda está só no roadmap.
Falhas de rede retornam silenciosamente 0/False. Tanto check_ping quanto check_port capturam qualquer exceção e devolvem um valor "neutro". Isso evita que o endpoint quebre, mas também esconde a diferença entre "a rede está realmente ruim" e "a checagem falhou por outro motivo" (por exemplo, falta de permissão para abrir socket ICMP bruto em ambientes sem privilégio).
Sem persistência. Cada chamada a /metrics é uma leitura pontual do momento exato da requisição; não existe histórico.
network-microservico/
├── Dockerfile
├── requirements.txt
├── app/
│ ├── main.py # endpoint /metrics
│ ├── core/
│ │ ├── metrics.py # CPU e RAM via psutil
│ │ └── network.py # ping e checagem de porta
│ ├── models/
│ │ └── schemas.py # reservado para modelos Pydantic, ainda vazio
│ └── tests/
│ └── test_metrics.py # criado, ainda sem casos implementados
└── diagramas/
├── DUSO.png
├── ERD.png
├── DiagramaClasse.png
├── dockerizado.png
└── roadmap_melhorias.png
| Tecnologia | Papel no projeto |
|---|---|
| FastAPI | Expõe o endpoint GET /metrics |
| Uvicorn | Servidor ASGI usado em desenvolvimento e dentro do container |
| psutil | Coleta uso de CPU e RAM do host |
| pythonping | Mede latência via ICMP |
| socket (stdlib) | Verifica se as portas 80 e 22 estão abertas |
| Docker | Empacota a aplicação para rodar em qualquer ambiente |
python-dotenv está no requirements.txt, mas hoje não é importado em nenhum arquivo do projeto — não há .env nem configuração via variável de ambiente ainda. Ainda não fiz essa limpeza.
git clone https://github.com/r0b3rTdk/network-microservico.git
cd network-microservico
python3 -m venv venv
source venv/bin/activate # Windows: venv\Scripts\Activate.ps1
pip install -r requirements.txt
uvicorn app.main:app --reloadAcesse http://127.0.0.1:8000/metrics.
docker build -t network-observer-microservice .
docker run -p 8000:8000 network-observer-microserviceAcesse http://localhost:8000/metrics.
app/tests/test_metrics.py existe na estrutura do repositório, mas está vazio — ainda não escrevi os casos de teste.
Hoje a validação é manual:
curl http://127.0.0.1:8000/metricsA resposta esperada tem dois blocos, system_metrics (CPU e RAM em porcentagem) e network_metrics (latência em ms e status booleano das portas 80 e 22 de google.com).
- A rota é
async def, mas todas as coletas internas são bloqueantes — cada requisição trava o event loop por pelo menos 1 segundo (o própriopsutil.cpu_percent(interval=1)), podendo chegar a vários segundos somando ping e portas. - Alvo de rede fixo em
google.com, sem forma de configurar outro host ou porta. python-dotenvestá listado nas dependências, mas não é usado em nenhum lugar do código.- Falha de rede e falta de permissão para socket ICMP bruto produzem o mesmo resultado (
0), sem diferenciação no retorno. - Nenhuma métrica é persistida — sem histórico.
- Endpoint aberto, sem autenticação.
- Sem testes automatizados.
- Não autentica as chamadas ao endpoint (planejado: API Key).
- Não monitora múltiplos alvos — só o host fixo usado como teste de conectividade.
- Não persiste métricas em banco, mesmo já tendo um ERD desenhado para isso.
- Não envia alertas ou notificações quando uma métrica ultrapassa um limite.
- Não tem testes automatizados.
- Não tem pipeline de CI/CD configurado.
- Adicionar autenticação via API Key no
/metrics, validando por variável de ambiente. - Tornar o host e as portas monitoradas configuráveis, em vez de fixos em
google.com. - Escrever os casos de teste em
test_metrics.py. - Mover as coletas bloqueantes para threadpool (
run_in_threadpool), pra não travar o event loop a cada chamada.
- Persistência das métricas coletadas, seguindo o modelo já desenhado no ERD, para permitir consulta histórica.
- Notificações (e-mail ou Slack) quando uma métrica ultrapassar um limite configurado.
- Monitoramento de múltiplos alvos numa única chamada, em vez de um host fixo.
- Métricas em formato Prometheus, para integrar com um Grafana.
- CI/CD rodando os testes e o build da imagem Docker a cada push.
A maior surpresa foi perceber, só depois de rodar a aplicação, que o interval=1 do psutil.cpu_percent() sozinho já impõe um segundo de espera em toda chamada — parece um parâmetro pequeno, mas define o piso de latência do endpoint inteiro.
Isso me ensinou na prática o que significa misturar código síncrono dentro de uma rota async do FastAPI: o event loop realmente fica bloqueado, não é só uma preocupação teórica de livro.
Colocar timeout curto no ping e no socket foi uma decisão simples de tomar, mas evitou que uma rede lenta travasse a API inteira por muito mais tempo do que o necessário.
Desenhar o ERD antes de precisar dele ajudou a pensar no roadmap com mais clareza, mesmo sabendo que a implementação da persistência ainda não veio.
Robert Emanuel
Desenvolvedor Back-end focado em Python, FastAPI, SQL, Docker e APIs REST.
GitHub: https://github.com/r0b3rTdk