Ryan.Bartsch
Ryan.Bartsch

Reputation: 4190

Use health check middleware in .NET Core Generic Host

Using the .NET Core Generic Host for an application that processes async messages.

The reason we're using the generic host instead of the .NET Core WebHost is because one of my colleagues had seen a few occasions where MassTransit (the light weight service bus framework that we're using) running as part of a .NET Core WebHost was not always shutting down gracefully on Linux after receiving a SIGTERM signal - we had to use SIGKILL to forcibly kill the process.

This application will run on Kubernetes and we want to implement a self-healing architecture using K8s liveness probes. In other .NET Core applications that use WebHost, we've used Health Checks that were introduced in .NET Core 2.2, but I don't know how to use middleware like this in a generic host.

In a WebHost I can configure the middleware as follows:

app.UseHealthChecks(appSettings.HealthChecksPath ?? "/health");

How would I go about doing this if using .NET Core Generic Host...

Kind regards.

Upvotes: 5

Views: 3711

Answers (2)

GreatOrdinary
GreatOrdinary

Reputation: 23

You don't need to create custom http listener. Here is I believe how its intended ( somedbcheck.cs class implements interface: Microsoft.Extensions.Diagnostics.HealthChecks.IHealthCheck):

using IHost host = Host.CreateDefaultBuilder(args)
        .UseSerilog(logger)
        .ConfigureServices((_, services) =>
            {
                //Configure generic host services
            }
        )
        .ConfigureWebHostDefaults(webBuilder =>
        {
        //This is where you are setting up webserver
            webBuilder.UseKestrel((c, options) =>
            {
                options.ListenAnyIP(config.Healthcheckport, listenoption =>
                {
                    listenoption.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http1AndHttp2;
                });
            });
        })
        .ConfigureWebHost(aa =>
        {
            //here you are specifying more details regarding endpoint mapping
            aa.UseStartup<WebHostStartup>();
        })
        .Build();
        
        
        
public class WebHostStartup
{
    private readonly AppSettings config;

    public WebHostStartup()
    {
        this.config = new AppSettings().GetSettings();  //your own parsed settings if you need it
    }
    public void ConfigureServices(IServiceCollection services)
    {
    //set up services associated with the webserver
        services.AddRouting();
        services.AddHealthChecks()
            .AddTypeActivatedCheck<SomeDbCheck>(nameof(SomeDbCheck)
                , failureStatus: HealthStatus.Unhealthy
                , tags: new[] { "startup", "ready" }
                , args: new object[] { config.ConnectionString })
            .AddCheck<LivenessCheck>(nameof(LivenessCheck), tags: new[] { "live" });
    }

    public void Configure(IApplicationBuilder app)
    {
    //Here set up the routing
        app.UseWhen(context => context.Connection.LocalPort == config.Healthcheckport,
            applicationBuilder =>
            {
                applicationBuilder.UseRouting();
                
                //applicationBuilder.UseAuthentication();
                applicationBuilder.UseEndpoints(endpoints =>
                {
                    endpoints.MapHealthChecks("/health");
                    endpoints.MapHealthChecks("/health/startup", new HealthCheckOptions
                    {
                        Predicate = healthCheck => healthCheck.Tags.Contains("startup")
                    });

                    endpoints.MapHealthChecks("/health/ready", new HealthCheckOptions
                    {
                        Predicate = healthCheck => healthCheck.Tags.Contains("ready")
                    });

                    endpoints.MapHealthChecks("/health/live", new HealthCheckOptions
                    {
                        Predicate = healthCheck => healthCheck.Tags.Contains("live")
                    });
                });
            });
    }
}

Upvotes: 1

Ryan.Bartsch
Ryan.Bartsch

Reputation: 4190

Solved this by using a HttpListener based health-check server - happy to be proven wrong, but AFAIK, Kestrel / ASP.NET Core middleware is not suitable for .NET 2.2 & generic host.

see here for code.

Upvotes: 3

Related Questions