Como implementar Health Checks para sua aplicação usando as extensões do ASP.NET Core 3.0
Aprenda a implementar Health Checks com as extensões do ASP.NET Core 3.0. Muito útil para configurar liveness probes do Kubernetes!

O ASP.NET Core 3.0
fornece uma forma bastante prática de implementar um endpoint para checar a saúde de uma aplicação.
Um endpoint de Health Check bem implementado pode nos ajudar de inúmeras formas a manter uma aplicação rodando. Podemos usá-los em conjunto com o liveness probes do Kubernetes, por exemplo, para que ele possa verificar a saúde de um serviço e assim poder reiniciá-lo caso as coisas dêem errado. Ferramentas de monitoramento também podem fazer uso desses endpoints para gerar alertas e estatísticas.
O pacote Microsoft.Extensions.Diagnostics.HealthChecks
traz uma abstração simples de implementar e colocar para funcionar na aplicação. Trata-se da interface IHealthCheck
.
Como podemos ver no snippet acima, o método CheckHealthAsync
recebe um objeto que representa o contexto da checagem de saúde da aplicação, do tipo HealthCheckContext
, e espera um resultado do tipo HealthCheckResult
.
Vamos nos ater primeiro ao retorno, que será mais comumente usado. Existem três status possíveis para a checagem:
- Healthy
- Degraded
- Unhealthy
O status Healthy
dispensa explicações, já que tudo está OK. Já o status Unhealthy
indica uma falha e pode inda detalhar a natureza dos erros identificados:
Como todos os argumentos são opcionais, podemos montar uma resposta dessas simplesmente assim:
O status Degraded
funciona exatamente da mesma forma. A diferença está no seu significado: o recurso está respondendo, mas a qualidade do serviço está abaixo do esperado, está degradada.
#Implementando um IHealthCheck
Vamos tomar por exemplo uma integração com um serviço externo do qual nossa aplicação depende. A implementação de uma validação dessas pode ser bastante simples, como esta a seguir, que toma a decisão com base numa requisição GET ao serviço externo:
Um caso de uso mais elaborado poderia decidir se a saúde do serviço está degradada de acordo com o tempo de resposta. Para isso, podemos utilizar a classe Stopwatch
como timer e assim tomar uma decisão:
O exemplo acima e bem próximo de uma implementação que fiz no trabalho e possui alguns detalhes interessantes para analisarmos. O primeiro ponto é o uso da sintaxe de pattern matching do C# 8 para selecionar o resultado da checagem com base em dois parâmetros: 1) o sucesso ou insucesso na consulta ao serviço externo, e 2) o tempo de resposta do serviço.
Esta é uma forma bem compacta de tratar todos os casos. Gosto dessa sintaxe porque fica muito fácil de identificar as combinações de entradas que levam a cada saída. Num post futuro, abordarei o pattern matching do C# em mais detalhes.
Seguindo no exemplo, se obtivermos sucesso na requisição (o primeiro parâmetro de cada tupla) e o tempo de resposta for de até 5 segundos, então consideramos que o serviço está saudável e retornamos HealthCheckResult.Healthy()
.
Já caso obtivermos sucesso, mas o tempo de resposta for superior a 5 segundos, então consideramos que está lento demais e retornamos HealthCheckResult.Degraded()
.
Se, no entanto, o status code retornado não for de sucesso, retornamos que não está saudável com HealthCheckResult.Unhealthy()
.
Além disso, temos um tratamento de exceção no código completo mais acima. Ele é totalmente opcional. Caso a checagem atire uma exceção, a API saberá que o serviço está Unhealthy
e vai retornar uma resposta de acordo.
Ainda assim, o HealthCheckResult
é construído de uma forma um pouco diferente aqui, usando o próprio construtor da classe:
Note que o primeiro argumento que passamos é o status de falha do contexto. A propriedade FailureStatus
terá o valor padrão Unhealthy
, a não ser que informado outro valor ao registrar este HealthCheck. E esta é uma oportunidade para explorarmos como é feito o registro do ServicoExternoHealthCheck
.
#Registrando um endpoint de Health Check
A configuração dos health checks é bastante simples e é feita em duas etapas. A primeira trata de registrar nossas implementações da interface IHealthCheck
. Isto é feito no método ConfigureServices
da classe Startup
.
Neste momento, podemos fazer algumas configurações adicionais para personalizar nosso health check. Por exemplo, podemos definir qual será o status quando ocorrer uma falha na verificação, como vimos um pouco acima.
Outra opção é passar uma coleção de tags para serem utilizadas durante a verificação de saúde do serviço:
Por fim, na segunda etapa da configuração, precisamos associar um endpoint para consulta. Isto é feito no método Configure
, ainda na classe Startup
:
E estamos prontos para testar! Basta subir a aplicação e fazer uma requisição GET no endpoint /health
. No caso de o status ser Healthy, note que a resposta tem Status HTTP 200 (OK):
Para o Degraded é a mesma coisa:
Já quando o serviço retorna Unhealthy, o Status HTTP retornado é o 503 (Serviço Indisponível):
#Como modificar o comportamento do Health Check
Ao registrar o endpoint de Health Check, também é possível informar um objeto do tipo HealthCheckOptions
.
Uma das opções mais interessantes que ele fornece é poder mudar o HTTP Status Code retornado para cada um dos três status de saúde (Healthy, Degraded e Unhealthy).
Se quisermos retornar um status 599 para Unhealthy, por exemplo, basta fazer assim:
Outra opção, é fornecer um filtro que decide dinamicamente quais Health Checks serão executados:
Também podemos customizar a resposta. Abaixo, temos um exemplo de configuração para retornar um JSON, mas poderíamos facilmente montar uma página de relatório HTML:
Felizmente, a biblioteca AspNetCore.HealthChecks.UI
já faz o trabalho de gerar um dashboard de acompanhamento. Não vou entrar em detalhes da configuração dessa ferramenta neste artigo, mas é bem simples.