Como Configurar Health Checks em ASP.NET Core
Por Tiago
Quando colocamos uma aplicação em produção, especialmente em ambientes distribuídos com containers e orquestradores como Kubernetes, surge uma pergunta recorrente: como saber, de forma automatizada, se a aplicação está realmente funcionando? Não basta o processo estar de pé — é preciso garantir que ela consegue responder requisições e que suas dependências (banco de dados, filas, APIs externas) estão saudáveis. É exatamente esse problema que os health checks do ASP.NET Core resolvem.
Neste post, vamos entender o que são health checks, como configurá-los do zero em uma aplicação ASP.NET Core, como criar verificações customizadas para dependências específicas e como integrar tudo isso com ferramentas de orquestração como Docker.
O que são health checks e por que usá-los
Health checks são endpoints HTTP expostos pela própria aplicação que informam seu estado de saúde. Esses endpoints são consumidos, geralmente, por sistemas externos de monitoramento, load balancers e orquestradores de containers — não por usuários finais navegando no sistema.
Existem alguns cenários típicos de uso:
- Sondas de liveness/readiness em orquestradores: ferramentas como Kubernetes usam esses endpoints para decidir se um container deve continuar recebendo tráfego, ser reiniciado, ou se um deploy em andamento deve ser interrompido.
- Roteamento de tráfego em load balancers: se uma instância reporta estado não saudável, o balanceador para de enviar requisições para ela, direcionando o tráfego para réplicas saudáveis.
- Monitoramento de recursos físicos: uso de memória, disco e outros recursos do servidor podem ser incluídos na verificação de saúde.
- Verificação de dependências externas: bancos de dados, APIs de terceiros, filas de mensagens — tudo que a aplicação precisa para funcionar corretamente pode (e deve) ser testado.
Antes de sair adicionando health checks em todo lugar, vale a pena pensar em qual sistema de monitoramento ou orquestração vai consumir essas informações. Isso influencia diretamente que tipos de verificação fazem sentido e como os endpoints devem ser estruturados.
Configuração básica
Para a maioria das aplicações, uma configuração simples que apenas informa se a aplicação está disponível para processar requisições (o que costuma ser chamado de liveness) já é suficiente.
A configuração básica envolve dois passos: registrar o serviço de health checks no container de injeção de dependência e mapear um endpoint HTTP que responde com o status de saúde.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddHealthChecks();
var app = builder.Build();
app.MapHealthChecks("/healthz");
app.Run();
Com isso, ao acessar /healthz, a aplicação retorna um texto simples representando o status atual, que pode ser:
Healthy— tudo funcionando normalmente;Degraded— a aplicação está operando, mas com alguma limitação ou lentidão;Unhealthy— algo está impedindo o funcionamento correto.
Nessa configuração mínima, nenhuma verificação específica de dependência está registrada — o middleware apenas confirma que a aplicação consegue responder à requisição naquele endpoint. Isso já é útil como sonda de liveness básica, mas na prática a maioria dos sistemas reais precisa de verificações mais específicas.
Adicionando verificações de dependências
O poder real dos health checks aparece quando combinamos essa infraestrutura com verificações específicas de cada dependência crítica da aplicação. É possível, por exemplo, verificar se o banco de dados está acessível, se uma fila de mensagens responde, ou se uma API externa está operacional.
Uma abordagem comum é implementar a interface IHealthCheck, que expõe um método CheckHealthAsync. Esse método deve retornar um HealthCheckResult indicando se aquela dependência específica está saudável, degradada ou indisponível.
public class BancoDeDadosHealthCheck : IHealthCheck
{
private readonly MeuDbContext _contexto;
public BancoDeDadosHealthCheck(MeuDbContext contexto)
{
_contexto = contexto;
}
public async Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context,
CancellationToken cancellationToken = default)
{
try
{
await _contexto.Database.CanConnectAsync(cancellationToken);
return HealthCheckResult.Healthy("Conexão com o banco OK.");
}
catch (Exception ex)
{
return HealthCheckResult.Unhealthy("Falha ao conectar ao banco.", ex);
}
}
}
Em seguida, basta registrar essa verificação junto com as demais:
builder.Services.AddHealthChecks()
.AddCheck<BancoDeDadosHealthCheck>("banco_de_dados");
Vale mencionar também que existe um ecossistema de pacotes comunitários (como AspNetCore.HealthChecks.SqlServer, AspNetCore.HealthChecks.Redis, entre outros) que já implementam verificações prontas para bancos de dados populares, sistemas de cache, mensageria e serviços de nuvem, evitando que você precise escrever tudo do zero.
Separando liveness e readiness com tags
Em ambientes orquestrados, é comum distinguir entre dois tipos de sonda:
- Liveness: responde se o processo da aplicação ainda está "vivo" — se estiver travado, o orquestrador pode reiniciar o container.
- Readiness: responde se a aplicação está pronta para receber tráfego — mesmo viva, ela pode estar temporariamente indisponível por conta de uma dependência fora do ar.
Para diferenciar esses dois cenários no mesmo projeto, uma técnica útil é usar tags nos health checks e filtrar quais verificações cada endpoint deve considerar:
builder.Services.AddHealthChecks()
.AddCheck<BancoDeDadosHealthCheck>("banco_de_dados", tags: new[] { "ready" });
app.MapHealthChecks("/health/live", new HealthCheckOptions
{
Predicate = _ => false // não executa nenhum check específico, só confirma que o processo responde
});
app.MapHealthChecks("/health/ready", new HealthCheckOptions
{
Predicate = check => check.Tags.Contains("ready")
});
Dessa forma, o endpoint /health/live serve como sonda de liveness simples (o processo responde), enquanto /health/ready executa de fato as verificações de dependências antes de declarar a aplicação pronta para receber tráfego.
Integrando com Docker
Containers Docker suportam uma diretiva nativa chamada HEALTHCHECK, que permite ao próprio Docker consultar periodicamente o endpoint de saúde da aplicação e reportar o status do container.
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
CMD curl --fail http://localhost:5000/healthz || exit 1
Com essa configuração, ferramentas como docker ps já mostram se o container está healthy ou unhealthy, e orquestradores que leem esse status podem tomar decisões automáticas, como reiniciar o container ou removê-lo de um pool de balanceamento.
Boas práticas
Algumas recomendações práticas para quando você for implementar health checks em projetos reais:
- Não exponha detalhes sensíveis nas respostas dos health checks públicos — evite vazar mensagens de exceção completas ou strings de conexão em ambientes acessíveis externamente.
- Separe liveness de readiness sempre que a aplicação tiver dependências externas, para evitar reinícios desnecessários de containers quando o problema é, na verdade, em um serviço terceiro.
- Defina timeouts curtos nas verificações de dependências, para que uma dependência lenta não trave a resposta do próprio endpoint de health check.
- Use tags para agrupar verificações por criticidade ou por tipo de sonda, facilitando a filtragem em diferentes endpoints.
Conclusão
Health checks são uma peça pequena, mas fundamental, na construção de aplicações resilientes e prontas para operar em ambientes modernos de infraestrutura. O ASP.NET Core torna essa implementação bastante direta: em poucas linhas já temos um endpoint funcional, e a partir daí é possível evoluir para verificações customizadas de dependências, segmentação entre liveness e readiness, e integração nativa com Docker e orquestradores.
Investir tempo nessa configuração logo no início do projeto evita dores de cabeça em produção — principalmente aquele tipo de incidente em que a aplicação "parece" estar de pé, mas na prática não consegue atender ninguém porque uma dependência crítica caiu silenciosamente.
Fontes
- Health checks in ASP.NET Core (Microsoft Learn) — documentação oficial da Microsoft sobre o middleware de health checks, configuração básica e integração com Docker.