ASP.NET Core: Health checks
If you’re using Kubernetes or load balancer, you need a tool, which can check that the application is still running. For these purposes, health checks provide an endpoint with the status of your application.
I’ve created a simple project on GitHub with examples of this post.
Health checks in ASP.NET Core 2.2
In this version of the framework, we have a built-in middleware provided health checks functionality. You need to put some lines in your Startup class:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddHealthChecks();
}
public void Configure(IApplicationBuilder app)
{
app.UseHealthChecks("/healthcheck");
}
}
Let’s make a simple request to http://localhost:5000/healthcheck
and check the result:
We see our application is Healthy
and response code is 200(OK)
.
Health checks UI
You can see application status not only by http-request, but it is also simple to add UI. You need to install this nuget-package and make some changes in the code:
public void ConfigureServices(IServiceCollection services)
{
services.AddHealthChecks();
services.AddHealthChecksUI();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseHealthChecks("/healthcheck", new HealthCheckOptions
{
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
app.UseHealthChecksUI();
}
"HealthChecks-UI": {
"HealthChecks": [
{
"Name": "HTTP-Api-Basic",
"Uri": "http://localhost:5000/healthcheck"
}
],
"EvaluationTimeOnSeconds": 60,
"MinimumSecondsBetweenFailureNotifications": 60
}
After that, we will have this mini dashboard on http://localhost:5000/healthchecks-ui
:
Update: There are some changes in .NET Core 3.0, which are caused by new routing system. You can find more details in the official documentation.
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddHealthChecks();
services.AddHealthChecksUI();
}
public void Configure(IApplicationBuilder app)
{
app.UseEndpoints(endpoints =>
{
endpoints.MapHealthChecks("/health", new HealthCheckOptions
{
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
});
app.UseHealthChecksUI();
}
}
Database health check
Let’s assume that your application has a reference to a third-party resource, for example, MongoDB and you want to know the status of this connection. Add this package to the project and add a method AddMongoDb(...)
:
public void ConfigureServices(IServiceCollection services)
{
services.AddHealthChecks()
.AddMongoDb(Configuration["MongoConnection:ConnectionString"]);
services.AddHealthChecksUI();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseHealthChecks("/healthcheck", new HealthCheckOptions
{
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
app.UseHealthChecksUI();
}
Now you can see a new item in the dashboard.
In this repository, you can find more packages for different databases and services. Furthermore, there is a package for the EF Core.
Create your own health check
What if you have a specific logic for a health check? Then you need to realize the IHealthCheck
interface. Let’s consider the example from Microsoft documentation:
public class ExampleHealthCheck : IHealthCheck
{
public ExampleHealthCheck()
{
}
public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken ct = default)
{
var healthCheckResultHealthy = true;
return healthCheckResultHealthy
? Task.FromResult(HealthCheckResult.Healthy("The check indicates a healthy result."))
: Task.FromResult(HealthCheckResult.Unhealthy("The check indicates an unhealthy result."));
}
}
public void ConfigureServices(IServiceCollection services)
{
services.AddHealthChecks()
.AddMongoDb(Configuration["MongoConnection:ConnectionString"])
.AddCheck<ExampleHealthCheck>("example_health_check");
services.AddHealthChecksUI();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseHealthChecks("/healthcheck", new HealthCheckOptions
{
ResponseWriter = UIResponseWriter.WriteHealthCheckUIResponse
});
app.UseHealthChecksUI();
}
As you can see, it’s straightforward to add a health check with custom logic.
Health checks by middleware
If you have a framework version smaller than 2.2, you can create a health check with the help of middleware.
public class HealthCheckMiddleware
{
private const string Path = "/healthcheck";
private readonly RequestDelegate _next;
public HealthCheckMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
if (!context.Request.Path.Equals(Path, StringComparison.OrdinalIgnoreCase))
{
await _next(context);
}
else
{
context.Response.ContentType = "text/plain";
context.Response.StatusCode = 200;
context.Response.Headers.Add(HeaderNames.Connection, "close");
await context.Response.WriteAsync("OK");
}
}
}
Add this middleware to the Startup
class of your project.
app.UseMiddleware<HealthCheckMiddleware>();
Health checks and Docker
Docker also has the support of health checks.
The HEALTHCHECK instruction tells Docker how to test a container to check that it is still working. This can detect cases such as a web server that is stuck in an infinite loop and unable to handle new connections, even though the server process is still running.
You need to add this instruction to your Dockerfile.
HEALTHCHECK --interval=5m --timeout=3s CMD curl -f http://localhost:80/healthcheck || exit 1
Now you can check the status of your container by command docker container ls
.
The status is healthy
.
Conclusion
Today we’ve looked at health checks. It’s a handy tool, especially if you are using multiple instances of your application. More information you can find in the GitHub repository and official docs, for example, health checks for different services, tools for pushing results or sending failure notifications.
Image: Photo by Annie Spratt on Unsplash
Comments