Monitoring ASP.NET Core Application Health with Health Checks š©ŗ
Your application isnāt just your code.
Itās your code plus your database.
Itās your code plus the services you use.
Itās your code plus the infrastructure you run on.
Failures in your application often are not just because the code you wrote is bad š, itās often because services or dependencies you depend on are having an issue.
Hereās an example: One of my clients has a relatively simple infrastructure. We have an ASP.NET Core application running in Microsoft Azure App Services, and we take advantage of Azure SQL, Azure Storage, and Azure Redis Cache (wowza Azure!!).
In addition āall Azure servicesā, we have a virtual machine (also running in Azure) that hosts a instance of Discourse.
How do I define how healthy my application? Itās not necessarily the health of one component, but the sum all the components!
If Azure SQL is down or have a blip, that impacts my overall system.
If Azure Redis Cache is upgrading, that impacts my overall system.
But how do you know WHICH component is the issue?
Introducing Health Checks
In earlier versions of ASP.NET Core, a new feature was introduced called Health Checks. This is a backend component which can regularly poll your services to see it theyāre healthy or not.
A sample health check looks something like this:
// Stolen from the ASP.NET Core Docs
public class ExampleHealthCheck : IHealthCheck
{
public Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context,
CancellationToken cancellationToken = default(CancellationToken))
{
var healthCheckResultHealthy = true;
if (healthCheckResultHealthy)
{
return Task.FromResult(
HealthCheckResult.Healthy("A healthy result."));
}
return Task.FromResult(
HealthCheckResult.Unhealthy("An unhealthy result."));
}
}
Imagine having a check for your SQL Server. AND your Redis Service. AND your storage provider. AND so on and so on!
Donāt want to write health checks yourself? Check out https://github.com/Xabaril/AspNetCore.Diagnostics.HealthChecks for an amazing list of managed health checks for a variety of platforms. I use these in my applications.
Here is an example of pulling health checks into your application:
// Startup.ConfigureServices()
services.AddHealthChecks()
.AddSqlServer(Configuration["SqlConnectionString"])
.AddRedis(Configuration["RedisConnectionString"])
.AddAzureBlobStorage(Configuration["CloudStorageConnectionString"])
.AddUrlGroup(new Uri(discourseUrl), "forums")
.AddApplicationInsightsPublisher();
Huge note for the above: I using the AspNetCore.Diagnostics.HealthChecks library to do all this work. I didnāt write any of the supported checks.
However, I can tell any of these checks what I define as healthy or unhealthy (although defaults are fine for me).
Finally, you turn it on by adding a health check route to your Configure() method.
// Startup.Configure
app.UseHealthChecks("/health")
What does this look like if you hit the endpoint?
{
"status": "Healthy",
"totalDuration": "00:00:00.0602633",
"entries": {
"sqlserver": {
"data": {},
"duration": "00:00:00.0019139",
"status": "Healthy"
},
"redis": {
"data": {},
"duration": "00:00:00.0017975",
"status": "Healthy"
},
"azureblob": {
"data": {},
"duration": "00:00:00.0067374",
"status": "Healthy"
},
"forums": {
"data": {},
"duration": "00:00:00.0586288",
"status": "Healthy"
}
}
}
Okay, cool - but thatās just testing uptime and connectivity
Youāre right! These health check examples are just a starting point, but each one of them are customizable.
For example, maybe for your SQL Server check, you might want to run a common query on your database to ensure the response time is within a designated period.
For our Discourse forums health check, I actually go much deeper than the example. Weāll check for a 200 OK from the server, as well as text on the website weāre expecting to see. Sometimes Discourse will show a temporarily warning if itās in a degraded state. If we see that, weāll report the forums as unhealthy.
What next?
Once you have a health check endpoint created, what do you do with it next?
Generally, when my clients report an issue, the health endpoint is the first thing Iāll hit to get a gut check. If one of the external dependencies is having an issue, I know where to start looking.
Azure App Services recently added a health endpoint polling feature thatāll look at the status of your endpoint across every node in your load balanced set. If one of the endpoints is degraded for a period of time, Azure will automatically restart the node!
Docker has had health checks support for a while, and itās useful to help manage which nodes are served traffic in a cluster. By the way, Iām not a Docker guy at all - but this is my understanding.
Wrapping up
Health Checks are a great way to Supercharge your ASP.NET Core applications. Just like the check engine light in your car, the system is constantly reporting on itself and youāll be able to identify issues faster and with more precision!
About Kevin
Kevin Griffin has been running production .NET applications and teaching developers for over two decades. A 16-time Microsoft MVP specializing in ASP.NET Core and Azure, Kevin brings real-world experience from his own SaaS products alongside his consulting work at Swift Kick. He's hosted the Hampton Roads .NET User Group since 2009 and founded RevolutionVA, the nonprofit behind Hampton Roads DevFest. Kevin's talks blend hard-won lessons from production systems with practical advice you can use Monday morning.
Categories