給 asp.net core 寫一個簡單的健康檢查
Intro
健康檢查可以幫助我們知道應用的當前狀態是不是處於良好狀態,現在無論是 docker 還是 k8s 還是現在大多數的服務注冊發現大多都提供了健康檢查機制來檢測應用的健康狀態,如果應用本身就提供一個健康檢查的機制會更友好,更能真實的反映出應用的健康狀態。
我們的開發環境虛擬機配置有點低,所以有時候虛擬機會卡死。。導致接口無響應,有時可能有些服務啟動有問題會掛掉,所以需要一個簡單的健康檢查機制去檢查應用的健康狀態來第一時間知道應用出現異常。
健康檢查擴展實現
public static IApplicationBuilder UseHealthCheck(this IApplicationBuilder applicationBuilder)
{
return UseHealthCheck(applicationBuilder, new PathString("/api/health"));
}
public static IApplicationBuilder UseHealthCheck(this IApplicationBuilder applicationBuilder, string path)
{
return UseHealthCheck(applicationBuilder, new PathString(path));
}
public static IApplicationBuilder UseHealthCheck(this IApplicationBuilder applicationBuilder, PathString path)
{
applicationBuilder.Map(path, builder => builder.Use(
(context, next) =>
{
context.Response.StatusCode = 200;
return context.Response.WriteAsync("healthy");
}));
return applicationBuilder;
}
public static IApplicationBuilder UseHealthCheck(this IApplicationBuilder applicationBuilder, string path, Func<IServiceProvider, bool> checkFunc)
{
return UseHealthCheck(applicationBuilder, new PathString(path), serviceProvider => Task.FromResult(checkFunc(serviceProvider)));
}
public static IApplicationBuilder UseHealthCheck(this IApplicationBuilder applicationBuilder, string path,
Func<IServiceProvider, Task<bool>> checkFunc)
{
return UseHealthCheck(applicationBuilder, new PathString(path), checkFunc);
}
public static IApplicationBuilder UseHealthCheck(this IApplicationBuilder applicationBuilder, PathString path, Func<IServiceProvider, bool> checkFunc)
{
if (checkFunc == null)
{
checkFunc = serviceProvider => true;
}
return UseHealthCheck(applicationBuilder, path, serviceProvider => Task.FromResult(checkFunc(serviceProvider)));
}
public static IApplicationBuilder UseHealthCheck(this IApplicationBuilder applicationBuilder, PathString path, Func<IServiceProvider, Task<bool>> checkFunc)
{
if (checkFunc == null)
{
checkFunc = serviceProvider => Task.FromResult(true);
}
applicationBuilder.Map(path, builder => builder.Use(
async (context, next) =>
{
try
{
var healthy = await checkFunc.Invoke(context.RequestServices);
if (healthy)
{
context.Response.StatusCode = StatusCodes.Status200OK;
await context.Response.WriteAsync("healthy");
}
else
{
context.Response.StatusCode = StatusCodes.Status503ServiceUnavailable;
await context.Response.WriteAsync("unhealthy");
}
}
catch (Exception ex)
{
context.RequestServices.GetService<ILoggerFactory>().CreateLogger("HealthCheck").Error(ex);
context.Response.StatusCode = StatusCodes.Status503ServiceUnavailable;
await context.Response.WriteAsync("unhealthy");
}
}));
return applicationBuilder;
}
配置健康檢查
在 Startup
里配置健康檢查,示例代碼
app.UseHealthCheck(); // 最基本的健康檢查, 默認檢查路徑為 ""/api/health",直接返回 healthy
app.UseHealthCheck("/heath"); // 配置健康檢查的路徑為 "/health",直接返回 healthy
app.UseHealthCheck("/health", serviceProvider =>
{
// 檢查數據連接是否正常,這里只是一個示例,可以根據需要自定義自己的實現
var configuration = serviceProvider.GetService<IConfiguration>();
var connString = configuration.GetConnectionString("DefaultConnection");
try
{
using (var conn = new SqlConnection(connString))
{
conn.EnsureOpen();
}
return true;
}
catch (Exception)
{
return false;
}
});
實際效果
直接啟動訪問 "/health"
數據庫連接改為一個錯誤的連接,修改數據庫名稱為一個不存在的數據庫
End
這個實現比較簡單,只是實現一個比較簡單的檢查,最初的想法比較簡單只是看某個應用是否正常工作,具體的檢查邏輯可以自定義。官方的 HealthChecks
的實現稍為復雜,下次單獨寫一篇文章介紹。