Nomenclaturas de health check em projetos modernos | API | CSharp
- Nomenclaturas de health check em projetos modernos | API | CSharp
Visão geral
Health check é um mecanismo usado para indicar se uma aplicação, serviço, container ou dependência está em condição adequada para operar.
Em projetos modernos, health check não significa apenas “a API respondeu 200”. Existem diferentes tipos de verificação, cada um com uma responsabilidade diferente:
| Nome | Pergunta que responde | Quem costuma usar |
|---|---|---|
health | O serviço está saudável de forma geral? | Monitoramento, dashboards, humanos |
live / liveness | O processo ainda está vivo ou travou? | Kubernetes, orchestrator |
ready / readiness | A aplicação está pronta para receber tráfego? | Load balancer, Kubernetes, gateway |
startup | A aplicação terminou a inicialização? | Kubernetes |
deep health | As dependências críticas estão funcionando? | Monitoramento, troubleshooting |
shallow health | A aplicação responde minimamente? | Orchestrator, balanceador |
dependency health | Banco, Redis, RabbitMQ, APIs externas estão acessíveis? | Observabilidade |
synthetic check | Um fluxo real do sistema funciona de ponta a ponta? | Monitoramento externo |
heartbeat | O componente ainda envia sinais de vida? | Workers, jobs, consumidores |
ping | A aplicação responde de forma simples? | Testes básicos, load balancer |
Health check
health é o nome mais genérico.
Normalmente representa um endpoint geral, como:
GET /health
Ele pode ser simples ou composto:
{
"status": "Healthy",
"checks": {
"database": "Healthy",
"redis": "Healthy",
"rabbitmq": "Degraded"
}
}
No ASP.NET Core, health checks são expostos como endpoints HTTP e podem ser usados por orquestradores, balanceadores de carga e ferramentas de monitoramento para avaliar o estado da aplicação e das dependências. (Microsoft Learn)
Para que serve
- Verificar o estado geral da aplicação
- Exibir informações para observabilidade
- Apoiar dashboards como Grafana, Datadog, New Relic, Prometheus ou Uptime Kuma
- Validar dependências principais
Quando usar
Use /health como endpoint geral para humanos, dashboards e ferramentas de monitoramento.
Liveness check
liveness responde à pergunta:
O processo ainda está vivo ou ficou preso em um estado irrecuperável?
Exemplo comum:
GET /health/live
No Kubernetes, se uma liveness probe falha, o container pode ser morto e reiniciado. A documentação mostra que, quando o comando ou endpoint configurado retorna falha, o kubelet considera o container não saudável e reinicia o container. (Kubernetes)
Para que serve
- Detectar deadlock
- Detectar processo travado
- Detectar loop infinito
- Detectar aplicação sem capacidade mínima de responder
- Forçar restart automático pelo orquestrador
O que não deve verificar
Evite colocar banco de dados, Redis, RabbitMQ ou API externa no liveness.
Se o banco cair e o liveness depender dele, o orquestrador pode reiniciar todos os containers da aplicação sem resolver o problema real.
Exemplo correto
GET /health/live
Resposta:
{
"status": "Healthy"
}
Regra prática
liveness deve responder:
Minha aplicação está viva o suficiente para continuar rodando?
Não deve responder:
Todas as minhas dependências estão funcionando?
Readiness check
readiness responde à pergunta:
A aplicação está pronta para receber tráfego agora?
Exemplo comum:
GET /health/ready
No Kubernetes, readiness probes servem para detectar quando a aplicação não deve receber tráfego. Um pod que não está pronto não recebe tráfego via Kubernetes Services. (Kubernetes)
Para que serve
- Remover uma instância do balanceamento
- Impedir tráfego durante startup
- Impedir tráfego quando dependências críticas estão indisponíveis
- Ajudar em deploy rolling update
- Evitar que uma instância receba requisições antes da hora
O que pode verificar
- Banco de dados
- Redis
- RabbitMQ
- Configurações obrigatórias carregadas
- Migrações aplicadas
- Cache inicial carregado
- Conexão com serviços internos críticos
Exemplo
{
"status": "Unhealthy",
"checks": {
"database": "Healthy",
"rabbitmq": "Unhealthy"
}
}
Nesse caso, a aplicação pode estar viva, mas não pronta.
Regra prática
readiness deve responder:
Posso receber tráfego de produção neste momento?
Startup check
startup responde à pergunta:
A aplicação já terminou sua inicialização?
Exemplo comum:
GET /health/startup
O Kubernetes usa startup probes para aplicações que demoram mais para iniciar. Depois que a startup probe passa, a liveness probe assume o papel de detectar travamentos. (Kubernetes)
Para que serve
- Evitar que aplicações lentas sejam reiniciadas antes de terminar o boot
- Separar tempo de inicialização de falha real
- Proteger aplicações que carregam cache, modelos, configurações ou conexões demoradas
- Evitar falsos positivos no
liveness
Quando usar
Use quando a aplicação demora para subir, por exemplo:
- API que carrega cache grande
- Serviço que precisa aquecer conexão
- Aplicação que valida configuração no boot
- Serviço que executa migração controlada
- Aplicação com inicialização pesada
Regra prática
startup deve responder:
O processo terminou a fase de boot?
Deep health
deep health é uma verificação mais profunda.
Exemplo:
GET /health/deep
Ela valida não apenas se a aplicação responde, mas também se as dependências importantes estão operacionais.
Para que serve
- Diagnóstico operacional
- Troubleshooting
- Painéis internos
- Verificação de dependências críticas
- Análise de degradação
Pode validar
- PostgreSQL
- SQL Server
- MongoDB
- Redis
- RabbitMQ
- Kafka
- APIs internas
- Storage
- Permissões
- Filas
- Backplane
- Configurações obrigatórias
Cuidado
Não use deep health como liveness.
Se uma dependência externa cair, isso não significa necessariamente que o processo da aplicação precisa ser reiniciado.
Shallow health
shallow health é uma verificação superficial.
Exemplo:
GET /health/shallow
Ela valida apenas se a aplicação consegue responder.
Para que serve
- Verificação rápida
- Baixo custo
- Uso por balanceadores
- Uso por orquestradores
- Evitar checks pesados em alta frequência
Exemplo de resposta
{
"status": "Healthy"
}
Diferença para deep health
| Tipo | Verifica dependências? | Custo | Uso recomendado |
|---|---|---|---|
shallow | Não | Baixo | Liveness, balanceador simples |
deep | Sim | Médio/alto | Monitoramento e diagnóstico |
Dependency health
dependency health verifica uma dependência específica.
Exemplos:
GET /health/database
GET /health/redis
GET /health/rabbitmq
GET /health/signalr-backplane
Para que serve
- Isolar falhas
- Saber exatamente qual dependência está indisponível
- Ajudar troubleshooting
- Separar falha da aplicação de falha de infraestrutura
Exemplo
{
"name": "postgres",
"status": "Healthy",
"latencyMs": 12
}
Boa prática
Evite expor detalhes sensíveis publicamente.
Esses endpoints devem ficar internos ou protegidos.
Ping
ping é a verificação mais simples possível.
Exemplo:
GET /ping
Resposta:
pong
Para que serve
- Testar se a aplicação responde
- Validar rota no gateway
- Validar DNS
- Validar roteamento
- Validar se o processo HTTP está aceitando conexão
Limitação
ping não prova que a aplicação está funcional.
Ele apenas indica que existe uma resposta básica.
Heartbeat
heartbeat é um sinal periódico enviado por um componente para dizer:
Ainda estou vivo.
Muito usado em:
- Workers
- Consumers
- Serviços background
- Clientes conectados
- Agentes locais
- Sistemas distribuídos
- SignalR, MQTT, WebSocket ou processos long-running
Exemplo
{
"service": "worker-publicacao-retorno",
"instanceId": "worker-01",
"status": "alive",
"timestamp": "2026-05-19T17:20:00Z"
}
Para que serve
- Saber se um worker ainda está ativo
- Detectar consumidores parados
- Detectar cliente desconectado
- Atualizar presença
- Monitorar agentes remotos
Diferença para health check
| Item | Health check | Heartbeat |
|---|---|---|
| Modelo | Alguém pergunta | O componente avisa |
| Direção | Pull | Push |
| Exemplo | Prometheus consulta /health | Worker publica “estou vivo” |
| Uso | APIs e serviços | Workers, consumidores e agentes |
Synthetic check
synthetic check é uma verificação que simula um fluxo real.
Exemplo:
- Fazer login
- Criar pedido fake
- Enviar comando de teste
- Consultar status
- Validar resposta
- Remover dados de teste
Para que serve
- Validar experiência real
- Detectar falhas que health check simples não detecta
- Monitorar jornada crítica
- Verificar integração de ponta a ponta
Exemplo
1. Envia comando de teste
2. Recebe requestId
3. Aguarda retorno
4. Confirma que o resultado chegou na fila
Cuidado
Synthetic checks devem ser controlados para não gerar dados inválidos, custo excessivo ou efeitos colaterais.
Status comuns
Em projetos modernos, os statuses mais comuns são:
| Status | Significado |
|---|---|
Healthy | Tudo certo |
Unhealthy | Falha crítica |
Degraded | Funciona parcialmente |
Unknown | Estado não determinado |
Starting | Inicializando |
NotReady | Vivo, mas não pronto para tráfego |
Timeout | Verificação excedeu o tempo limite |
No Docker, o HEALTHCHECK usa código de saída para indicar saúde do container: 0 significa saudável, 1 significa não saudável, e 2 é reservado. (Docker Documentation)
Nomenclatura recomendada para APIs HTTP
Uma estrutura clara seria:
GET /health
GET /health/live
GET /health/ready
GET /health/startup
GET /health/deep
GET /health/dependencies
GET /ping
Sugestão prática
| Endpoint | Uso |
|---|---|
/ping | Teste simples de conectividade |
/health/live | Liveness probe |
/health/ready | Readiness probe |
/health/startup | Startup probe |
/health | Estado geral |
/health/deep | Diagnóstico interno completo |
/health/dependencies | Estado das dependências |
Diferença entre health, live e ready
| Endpoint | Verifica | Pode reiniciar container? | Pode remover do tráfego? | Deve verificar banco? |
|---|---|---|---|---|
/health/live | Processo vivo | Sim | Não necessariamente | Não |
/health/ready | Pronto para tráfego | Não | Sim | Sim, se for crítico |
/health/startup | Boot finalizado | Sim, se nunca subir | Sim | Depende |
/health | Estado geral | Não diretamente | Não diretamente | Pode |
/health/deep | Diagnóstico completo | Não | Não diretamente | Sim |
Exemplo em .NET
using Microsoft.AspNetCore.Diagnostics.HealthChecks;
using Microsoft.Extensions.Diagnostics.HealthChecks;
var builder = WebApplication.CreateBuilder(args);
builder.Services
.AddHealthChecks()
.AddCheck("self", () => HealthCheckResult.Healthy(), tags: ["live"])
.AddCheck("startup", () => HealthCheckResult.Healthy(), tags: ["startup"])
.AddNpgSql(
builder.Configuration.GetConnectionString("Postgres")!,
name: "postgres",
tags: ["ready", "deep", "dependencies"]);
var app = builder.Build();
app.MapGet("/ping", () => Results.Ok("pong"));
app.MapHealthChecks("/health");
app.MapHealthChecks("/health/live", new HealthCheckOptions
{
Predicate = check => check.Tags.Contains("live")
});
app.MapHealthChecks("/health/ready", new HealthCheckOptions
{
Predicate = check => check.Tags.Contains("ready")
});
app.MapHealthChecks("/health/startup", new HealthCheckOptions
{
Predicate = check => check.Tags.Contains("startup")
});
app.MapHealthChecks("/health/deep", new HealthCheckOptions
{
Predicate = check => check.Tags.Contains("deep")
});
app.Run();
Exemplo com Kubernetes
apiVersion: apps/v1
kind: Deployment
metadata:
name: minha-api
spec:
replicas: 3
selector:
matchLabels:
app: minha-api
template:
metadata:
labels:
app: minha-api
spec:
containers:
- name: minha-api
image: minha-api:latest
ports:
- containerPort: 8080
startupProbe:
httpGet:
path: /health/startup
port: 8080
failureThreshold: 30
periodSeconds: 10
livenessProbe:
httpGet:
path: /health/live
port: 8080
initialDelaySeconds: 10
periodSeconds: 10
failureThreshold: 3
readinessProbe:
httpGet:
path: /health/ready
port: 8080
initialDelaySeconds: 5
periodSeconds: 10
failureThreshold: 3
O Kubernetes permite probes HTTP, TCP e gRPC. A própria documentação mostra liveness por HTTP, TCP e gRPC, e o gRPC ficou estável para probes a partir do Kubernetes v1.27. (Kubernetes)
Exemplo com Docker Compose
services:
minha-api:
image: minha-api:latest
ports:
- "8080:8080"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health/live"]
interval: 30s
timeout: 5s
retries: 3
start_period: 20s
No Docker Compose, healthcheck declara o comando usado para determinar se o container está saudável, podendo configurar interval, timeout, retries, start_period e start_interval. (Docker Documentation)
Exemplo com gRPC
Em serviços gRPC, existe um protocolo padrão de health checking. O servidor expõe um serviço de health check e o cliente pode usar esse estado para evitar enviar chamadas para backends não saudáveis. (gRPC)
Estados comuns no gRPC health checking:
| Status | Significado |
|---|---|
SERVING | Serviço disponível |
NOT_SERVING | Serviço indisponível |
UNKNOWN | Estado desconhecido |
Exemplo conceitual:
grpc.health.v1.Health/Check
Resposta:
{
"status": "SERVING"
}
Como escolher o nome correto
| Cenário | Nome recomendado |
|---|---|
| Quero saber se a API responde | /ping |
| Quero saber se o processo travou | /health/live |
| Quero saber se pode receber tráfego | /health/ready |
| Quero proteger aplicação lenta no boot | /health/startup |
| Quero ver estado geral | /health |
| Quero validar dependências críticas | /health/deep |
| Quero validar banco isoladamente | /health/database |
| Quero validar Redis isoladamente | /health/redis |
| Quero validar fluxo real de negócio | synthetic check |
| Quero saber se worker está vivo | heartbeat |
Boas práticas
- Não coloque dependências externas no
liveness. - Use
readinesspara tirar a instância do tráfego sem reiniciar. - Use
startuppara aplicações que demoram para inicializar. - Use
deep healthapenas para diagnóstico e monitoramento interno. - Não exponha detalhes de banco, host, string de conexão ou exceções em endpoints públicos.
- Configure timeout curto para cada dependência.
- Evite health checks pesados em alta frequência.
- Separe status operacional de status de negócio.
- Retorne HTTP
200para saudável e503para indisponível. - Em APIs públicas, exponha apenas o mínimo necessário.
- Em dashboards internos, exponha detalhes por dependência.
Exemplo de estratégia recomendada
Para uma API moderna em .NET atrás de APISIX, Nginx, Kubernetes, Docker Swarm ou Load Balancer:
| Endpoint | Público? | Usado por | Verifica |
|---|---|---|---|
/ping | Sim | Gateway / teste manual | Resposta simples |
/health/live | Interno | Orquestrador | Processo vivo |
/health/ready | Interno | Load balancer / gateway | Pronto para tráfego |
/health/startup | Interno | Orquestrador | Inicialização |
/health | Interno | Monitoramento | Estado geral |
/health/deep | Não | Observabilidade interna | Dependências |
/metrics | Não | Prometheus | Métricas |
Exemplo de erro comum
Errado
app.MapHealthChecks("/health/live", new HealthCheckOptions
{
Predicate = _ => true
});
Esse exemplo faz o liveness validar tudo, incluindo banco, Redis, RabbitMQ e APIs externas.
Se o banco cair, o container pode ser reiniciado sem necessidade.
Melhor
app.MapHealthChecks("/health/live", new HealthCheckOptions
{
Predicate = check => check.Tags.Contains("live")
});
app.MapHealthChecks("/health/ready", new HealthCheckOptions
{
Predicate = check => check.Tags.Contains("ready")
});
Assim:
/health/livevalida se o processo está vivo/health/readyvalida se a aplicação pode receber tráfego
Resumo rápido
| Nome | Serve para |
|---|---|
ping | Verificar resposta mínima |
health | Estado geral |
liveness | Saber se deve reiniciar |
readiness | Saber se deve receber tráfego |
startup | Proteger inicialização lenta |
deep health | Diagnóstico completo |
shallow health | Verifica ção leve |
dependency health | Verificar dependência específica |
heartbeat | Sinal periódico de vida |
synthetic check | Simular fluxo real |