值得看看 ASP.NET Core 应用健康检查

176 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第2天,点击查看活动详情

2.2版本之后,asp.net core 提供了健康检查组件,通过以下对Startup类简单修改就可以达到目的(只是应用运行状态)

public void ConfigureServices(IServiceCollection services)
{
    //使用该扩展方法
    services.AddHealthChecks();
}

public void Configure(IApplicationBuilder app)
{
    app.UseRouting();

    app.UseEndpoints(endpoints =>
    {
        //使用该扩展方法
        endpoints.MapHealthChecks("/health");
    });
}

此时我们可以访问 "/health" 路径,将会看到对应结果:

image.png

如果程序正常,则返回Http状态码为200,显示内容为"Healthy"的结果。如果程序不正常,则返回Http状态码为503,显示内容为"UnHealthy"的结果。

最初我们只是简单的引入了 AddHealthChecks 。 但是它并没有任何特定的逻辑在里面。而现实场景我们是需要对各种指标进行检查的,就好比体检单上有多个体检项一样。所以我们需要实现自定义的检查功能。

比如咱们现在要实现一个对MySql连接情况的检查。我们只需要实现 IHealthCheck 接口,实现CheckHealthAsync 方法就可以了:

public class MySqlHealthCheck : IHealthCheck 
{ 
    private readonly MySqlConnection _connection; 
    public MySqlHealthCheck(MySqlConnection connection) 
   { 
        _connection = connection; 
   } 
   public Task<HealthCheckResult> CheckHealthAsync( 
                      HealthCheckContext context, 
                     CancellationToken cancellationToken = default) 
   { 
             try 
             { 
                   _connection.Open(); 
             } 
            catch (MySqlException ex) 
              { 
                  return Task.FromResult(HealthCheckResult.Unhealthy("mysql数据库连接异常")); 
              } 
              return Task.FromResult(HealthCheckResult.Healthy()); 
   } 
}

然后在Startup.cs 的AddHealthChecks进行扩展:

services.AddHealthChecks()
        .AddCheck<MySqlHealthCheck>("mysql_check");

此时如果咱们再次访问"/health" 路径,就会发现应用会执行MySqlHealthCheck里面的检查逻辑。

但是实际情况,咱们往往都会有许许多多的检查项,比如增加一个叫做MemoryHealthCheck的检查项:

public class MemoryHealthCheck : IHealthCheck
{
    public Task<HealthCheckResult> CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = default)
    {
        //doing some memory check things.
        return Task.FromResult(HealthCheckResult.Healthy());
    }
}

// startup.cs
public void ConfigureServices(IServiceCollection services)
{
    services.AddHealthChecks()
            .AddCheck<MySqlHealthCheck>("mysql_check")
            .AddCheck<MemoryHealthCheck>("memory_check");  // add this line
}

或许还有许许多多的检查项:FileSizeHealthCheckRedisHealthCheck等等。当我们将它们都添加上之后,则只有当所有的检查器都返回为Healthy的时候,才会认为是健康

但是某些情况我们又只想进行单项检查怎么办呢? 我们可以在 endpoints 的配置中新增另外的路由映射规则:

// startup.cs
 app.UseEndpoints(endpoints =>
{
    endpoints.MapHealthChecks("/health", new HealthCheckOptions()
    {
        Predicate = s => s.Name.Equals("sql_check"),
        ResponseWriter = WriteResponse
    });

    endpoints.MapHealthChecks("/healthy", new HealthCheckOptions()
    {
        Predicate = s => s.Name.Equals("memory_check"),
        ResponseWriter = WriteResponse
    });
});

//指定返回格式
private static Task WriteResponse(HttpContext context, HealthReport result)
{
    context.Response.ContentType = "application/json";

    var json = new JObject(
        new JProperty("status", result.Status.ToString()),
        new JProperty("results", new JObject(result.Entries.Select(pair =>
            new JProperty(pair.Key, new JObject(
                new JProperty("status", pair.Value.Status.ToString()),
                new JProperty("description", pair.Value.Description),
                new JProperty("data", new JObject(pair.Value.Data.Select(
                    p => new JProperty(p.Key, p.Value))))))))));

    return context.Response.WriteAsync(
        json.ToString());
}

我们在原有的基础上增加了HealthCheckOptions的参数,该参数指定了关于状态检测的匹配规则,返回状态码,返回格式等信息。

上面的代码我们指定了两个路由。当访问"health"路径的时候,则是对sql连接的检查(根据检查器名来匹配:Name.Equals("mysql_check") ),而访问"healthy"路径的时候,是对内存的检查。 最后还为他们指定了需要返回的内容(WriteResponse)。

接下来我们再次进行请求"health"路径,就会得到检查结果json响应

另外很高兴的告诉大家有第三方AspNetCore.Diagnostics.HealthChecks包为我们做了很多类型的检查,不用自己去实现IHealthCheck接口

PS:现在是不是觉得NetCore开源之后各种开发特性实现起来很优雅呢!