An Interest In:
Web News this Week
- April 25, 2024
- April 24, 2024
- April 23, 2024
- April 22, 2024
- April 21, 2024
- April 20, 2024
- April 19, 2024
Implementing health checks PT.1 - Asp.Net Core 6 configuration
When a production running application is not available to the customers due to technical issues, we are not just losing money but also faith that customers have in our product. In fact, they may spread a bad word about our product on social media, friends or store reviews or - even worst - move to competitors.
Basically, when an application is not available to the stakeholders, it doesn't exist.
Of course it may happen. It might because of a human mistake, an erroneous configuration or a bug. Or maybe because our cloud provider has some kind issues.
For these reason, we must know immediately when application goes offline.
One of the most used and simplest techniques are health checks endpoint.
An health check endpoint, is an API exposed by an application that has no logic except for replying with a positive status code; if the caller doesn't receive any response or the status code is not the one expected, it means there is an error and an alert must be sent using the technology of your choice (email, push notification.. SMS and so on).
Of course, Asp.Net Core provides a built-in mechanism to implement an health check endpoint.
Implementing a simple health check endpoint
Create an Asp.Net Core project. For this demo (you can find the source code at the end of this post) I am going to use dotnet 6 with the new minimal host startup template.
Install the NuGet package Microsoft.Extensions.Diagnostics.HealthChecks
and configurate it:
var builder = WebApplication.CreateBuilder(args);builder.Services.AddHealthChecks();var app = builder.Build();app.MapHealthChecks("/alive");app.Run();
Run the application and navigate to localhost:<port>/alive
and you should see something like this:
You if you try to call the same endpoint with Postman or a similar tool, you see the status code is 200 OK
.
Hurrah, the health check endpoint is ready to be regularly consumed!
Advanced scenario
It might be a scenario where the application is online but for some reason, it can't communicate with a database. Potentially it is a big disservice to our customers and it is likely that users cannot perform almost all of the actions. It would be better to get notified immediately.
Entity Framework Health Checks
Also Entity Framework provides a built-in mechanism to monitor the connectivity between an application and the SQL instance database.
NB: to go ahead, of course you must have Entity Framework configured and pointing to a running SQL database
Install the package Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore
from NuGet and configure it:
services.AddHealthChecks().AddDbContextCheck<MyDbContext>("/dbcontext");
Running the application and pointing again to localhost:<port>/alive
you should have the same result:
By the default, under the hood it checks for:
The DbContextHealthCheck calls EF Core's CanConnectAsync method. You can customize what operation is run when checking health using AddDbContextCheck method overloads.
The name of the health check is the name of the TContext type.
It now works but there is still a problem: no matter what health check endpoint we hit (/alive
or /dbcontext
), both checks are performed so exposing two different APIs is useless.
How is it possible to set different endpoints for different checks? The answer is, through checks names.
Change the endpoints registration as follow:
const string ALIVE = "alive";const string ALIVE_DBCONTEXT = "dbcontext";...builder.Services.AddHealthChecks().AddDbContextCheck<MyDbContext>(name: ALIVE_DBCONTEXT);app.MapHealthChecks( "/alive", new HealthCheckOptions { Predicate = (c) => c.Name == ALIVE });app.MapHealthChecks( "/dbcontext", new HealthCheckOptions { Predicate = (c) => c.Name == ALIVE_DBCONTEXT });
In this case, we are giving a name to a specific health check endpoint. When the name is matched, the health check is executed.
To have a confirmation, we can do a test:
- run the application and the database in a local Docker container
- navigate to
localhost:<port>/alive
: you should getHealthy
as result - stop the database container and refresh the page: you should still get
Healthy
as result - navigate to
localhost:<port>/dbcontext
: you should getUnhealthy
as result - restart the database container and refresh the page: you should get
Healthy
as result
Custom checks: Azure Cosmos DB
Asp.Net allows to define some custom code while performing an health check. This is the case where we can test our connection to an Azure Cosmos DB instance, because the .NET SDK doesn't provide any mechanism to check the connection between the application and the database service.
The following example tests the connection using container.ReadContainerAsync()
, a method that needs database access to be executed.
// Cosmos initializationbuilder.Services .AddHealthChecks() .AddDbContextCheck<MyDbContext>(name: ALIVE_DBCONTEXT) .AddCheck<CosmosHealthChecker>(name: ALIVE_COSMOS);...app.MapHealthChecks( "/cosmos", new HealthCheckOptions { Predicate = (c) => c.Name == ALIVE_COSMOS }); public class CosmosHealthChecker : IHealthCheck { private readonly IServiceScopeFactory _serviceScopeFactory; private readonly IConfiguration _configuration; private readonly ILogger<CosmosHealthChecker> _logger; public CosmosHealthChecker( IServiceScopeFactory scopeFactory, IConfiguration configuration, ILogger<CosmosHealthChecker> logger) { _serviceScopeFactory = scopeFactory; _configuration = configuration; _logger = logger; } public async Task<HealthCheckResult> CheckHealthAsync( HealthCheckContext context, CancellationToken cancellationToken = default) { try { string collectionName = _configuration["Cosmos:Collection"]; using IServiceScope scope = _serviceScopeFactory.CreateScope(); Database db = scope.ServiceProvider.GetRequiredService<Database>(); Container container = db.GetContainer(collectionName); await container.ReadContainerAsync(cancellationToken: cancellationToken); return new HealthCheckResult(HealthStatus.Healthy); } catch (Exception ex) { _logger.LogError(ex, "Error pinging Cosmos db"); return new HealthCheckResult( context.Registration.FailureStatus, "An unhealthy result."); } } }
Conclusions
We understood how much having an alerting system that notify us when users can't access our service is important and that we need to put effort in it.
This post explains how we can provide some health check endpoints in an Asp.Net project with just few lines of code
As usual the source code is available in my GitHub profile.
Photo by Bruno Nascimento on Unsplash
Original Link: https://dev.to/krusty93/implementing-health-checks-pt1-aspnet-core-6-configuration-6gp
Dev To
An online community for sharing and discovering great ideas, having debates, and making friendsMore About this Source Visit Dev To