DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • GDPR Compliance With .NET: Securing Data the Right Way
  • How to Enhance the Performance of .NET Core Applications for Large Responses
  • Developing Minimal APIs Quickly With Open Source ASP.NET Core
  • Revolutionizing Content Management

Trending

  • Scalable, Resilient Data Orchestration: The Power of Intelligent Systems
  • Unlocking AI Coding Assistants Part 1: Real-World Use Cases
  • Optimize Deployment Pipelines for Speed, Security and Seamless Automation
  • Rethinking Recruitment: A Journey Through Hiring Practices
  1. DZone
  2. Software Design and Architecture
  3. Cloud Architecture
  4. Health Checks with ASP.NET Core and Kubernetes

Health Checks with ASP.NET Core and Kubernetes

Learn more about the difference between readiness and liveness checks, then learn how to run these checks using ASP.Net Core and Kubernetes.

By 
David Guida user avatar
David Guida
·
Apr. 03, 20 · Tutorial
Likes (5)
Comment
Save
Tweet
Share
19.0K Views

Join the DZone community and get the full member experience.

Join For Free

Health checks are a fundamental part of our APIs. I guess they fall in that category of "non-functional-but-heavily-required" things. More or less like a good part of the infrastructure code.

They don't add business value per se but have an enormous impact for those in IT, like DDD and design patterns. You can normally see them in conjunction with container orchestration or monitoring tools to ensure that the system is alive and kicking.

There are mainly two categories of health checks: readiness and liveness.

Readiness health checks perform an in-depth check of all the application dependencies, such as databases, external services and so on. The system is booting and alive but not yet ready to serve incoming requests.

Liveness health checks are instead used to signal that the application is ready to serve traffic. They should execute fairly quickly and serve as an immediate probe to ensure everything is fine.

The idea is to first run the readiness checks. If they pass, rely only on the liveness ones for a specific amount of time.

A successful health check should return a 200 HTTP status and a basic report, especially for the readiness ones.

Setting up checks in an ASP.NET Core project is fairly easy. Just add a call to services.AddHealthChecks() in the ConfigureServices() method of our Startup.cs .

On GitHub, there are a few interesting repositories that add some nice extension methods. AspNetCore.Diagnostics.HealthChecks is one of the most famous, exposing checks for a wide range of systems like SQL Server, MySql, Oracle, Kafka, Redis, and many others.

Once you've registered the checks on the DI Container, the next step is to expose the endpoint:

C#
 




xxxxxxxxxx
1


 
1
public void Configure(IApplicationBuilder app)
2
{
3
    app.UseEndpoints(endpoints =>
4
    {
5
        endpoints.MapHealthChecks("/ops/health");
6
    });
7
}



This is the simplest example possible, however, the  MapHealthChecks() methods also give us the ability to customize the output by specifying a Response Writer:

C#
 




xxxxxxxxxx
1
54


 
1
public void Configure(IApplicationBuilder app)
2
{
3
    var healthCheckOptions = new HealthCheckOptions()
4
    {
5
        ResponseWriter = WriteReadinessResponse
6
    };
7

          
8
    app.UseEndpoints(endpoints =>
9
    {
10
        endpoints.MapHealthChecks("/ops/health", healthCheckOptions);
11
    });
12
}
13

          
14
private static Task WriteReadinessResponse(HttpContext context, HealthReport result)
15
{
16
    context.Response.ContentType = "application/json; charset=utf-8";
17

          
18
    var options = new JsonWriterOptions
19
    {
20
        Indented = true
21
    };
22

          
23
    using (var stream = new MemoryStream())
24
    {
25
        using (var writer = new Utf8JsonWriter(stream, options))
26
        {
27
            writer.WriteStartObject();
28
            writer.WriteString("status", result.Status.ToString());
29
            writer.WriteStartObject("results");
30
            foreach (var entry in result.Entries)
31
            {
32
                writer.WriteStartObject(entry.Key);
33
                writer.WriteString("status", entry.Value.Status.ToString());
34
                writer.WriteString("description", entry.Value.Description);
35
                writer.WriteStartObject("data");
36
                foreach (var item in entry.Value.Data)
37
                {
38
                    writer.WritePropertyName(item.Key);
39
                    JsonSerializer.Serialize(
40
                        writer, item.Value, item.Value?.GetType() ??
41
                        typeof(object));
42
                }
43
                writer.WriteEndObject();
44
                writer.WriteEndObject();
45
            }
46
            writer.WriteEndObject();
47
            writer.WriteEndObject();
48
        }
49

          
50
        var json = Encoding.UTF8.GetString(stream.ToArray());
51

          
52
        return context.Response.WriteAsync(json);
53
    }
54
}


Based on the checks you've added, this should return something like this:

C#
 




xxxxxxxxxx
1
10


 
1
{
2
  "status": "Healthy",
3
  "results": {
4
    "db": {
5
      "status": "Healthy",
6
      "description": null,
7
      "data": {}
8
    }
9
  }
10
}


Now, I mentioned "container orchestration" at the beginning of this article. This tends to be synonymous with Kubernetes, which has its own configuration for health checks. In your configuration.yml file you can specify both liveness and readiness:

C#
 




xxxxxxxxxx
1
18


 
1
readinessProbe:
2
    httpGet:
3
        path: /health/readiness
4
        port: 80
5
    initialDelaySeconds: 10
6
    timeoutSeconds: 30
7
    periodSeconds: 60
8
    successThreshold: 1
9
    failureThreshold: 5
10
livenessProbe:
11
    httpGet:
12
        path: /health/liveness
13
        port: 80
14
    initialDelaySeconds: 10
15
    timeoutSeconds: 5
16
    periodSeconds: 15
17
    successThreshold: 1
18
    failureThreshold: 3


A few things to note here. First of all, the endpoints are different. As we discussed previously, we can (and should) split our checks in order to let the liveness checks to run as quickly as possible. 

This can be accomplished, for example, by simply skipping all the checks and returning a 200 right away:

C#
 




xxxxxxxxxx
1


 
1
endpoints.MapHealthChecks("/health/readiness", healthCheckOptions);
2

          
3
endpoints.MapHealthChecks("/health/liveness", new HealthCheckOptions(){
4
    Predicate = (_) => false
5
});



That Predicate allows filtering the checks based on various conditions like name or tags. Yes, those are a thing and can be specified. More details here.

Going back to our Kubernetes config, another thing worth mentioning is the different settings used for the checks. For example, timeoutSeconds is higher when probing for readiness as we are making sure that all our dependencies are alive. The same thing applies for periodSeconds: we want liveness checks to be executed more often.

Moreover, don't forget that if the failureThreshold is surpassed for liveness, the Pod will be killed. Failing readiness will cause the pod to be marked as Unhealthy instead, and not receive traffic any more.

ASP.NET Kubernetes Health (Apple) ASP.NET Core

Opinions expressed by DZone contributors are their own.

Related

  • GDPR Compliance With .NET: Securing Data the Right Way
  • How to Enhance the Performance of .NET Core Applications for Large Responses
  • Developing Minimal APIs Quickly With Open Source ASP.NET Core
  • Revolutionizing Content Management

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!