1. 程式人生 > >給 asp.net core 寫一個簡單的健康檢查

給 asp.net core 寫一個簡單的健康檢查

給 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 的實現稍為複雜,下次單獨寫一篇文章介紹。