ASP.NET Core 2.2 به همراه تعدادی قابلیت جدید است که یکی از آنها بررسی سلامت برنامه یا Health Check نام دارد. در بسیاری از اوقات ممکن است از سرویسهای ping و یا درخواست مشاهدهی صفحات وب سایت در بازههای زمانی مشخصی، جهت اطمینان حاصل کردن از برپایی و سلامت آن استفاده کنید. اما این سرویسها الزاما وضعیت سلامت برنامه را نمیتوانند به خوبی گزارش کنند. به همین جهت امکان ارائهی گزارشهای دقیقتری توسط ویژگی Health Check به ASP.NET Core اضافه شدهاست.
پیاده سازی ویژگی Health Check بدون استفاده از قابلیتهای ASP.NET Core 2.2
اگر بخواهیم در بررسی سلامت برنامه، وضعیت بانک اطلاعاتی آنرا گزارش دهیم، میتوان یک چنین اکشن متدی را طراحی کرد که در آن اتصالی به بانک اطلاعاتی باز شده و اگر در حین فراخوانی مسیر working/، استثنائی رخ داد، با بازگشت status code مساوی 503، عدم سلامت برنامه اعلام شود؛ کاری که سرویسهای ping متداول نمیتوانند آنرا با این دقت انجام دهند:
[Route("working")]
public ActionResult Working()
{
using (var connection = new SqlConnection(_connectionString))
{
try
{
connection.Open();
}
catch (SqlException)
{
return new HttpStatusCodeResult(503, "Generic error");
}
}
return new EmptyResult();
}
بازنویسی قطعه کد فوق با ویژگی جدید Health Check در ASP.NET Core 2.2
اکنون اگر بخواهیم قطعه کد فوق را با کمک ویژگیهای جدید ASP.NET Core 2.2 بازنویسی کنیم، روش کار به صورت زیر خواهد بود:
namespace MvcHealthCheckTest
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddHealthChecks()
.AddCheck("sql", () =>
{
using (var connection = new SqlConnection(Configuration["connectionString"]))
{
try
{
connection.Open();
}
catch (SqlException)
{
return HealthCheckResult.Unhealthy();
}
}
return HealthCheckResult.Healthy();
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseHealthChecks("/working");
- ابتدا توسط متد services.AddHealthChecks، سرویس بررسی سلامت برنامه، ثبت و معرفی میشود.
- سپس توسط متد app.UseHealthChecks، بدون اینکه نیاز باشد کنترلر و اکشن متد جدیدی را جهت بازگشت وضعیت سلامت برنامه، تعریف کنیم، مسیر working/ قابل دسترسی خواهد شد.
تا اینجا اگر این مسیر را به سرویس بررسی uptime برنامهی خود معرفی کنید، صرفا وضعیت قابل دسترسی بودن مسیر working/ را دریافت خواهید کرد. اگر نیاز به گزارش دقیقتری وجود داشت، میتوان به کمک متد AddCheck، یک منطق سفارشی را نیز به آن افزود؛ همانند بررسی امکان اتصال به بانک اطلاعاتی، به روشی که ملاحظه میکنید. در اینجا اگر منطق مدنظر با موفقیت اجرا شد، HealthCheckResult.Healthy بازگشت داده میشود و یا HealthCheckResult.Unhealthy در صورت عدم موفقیت. هر کدام از این متدها میتوانند توضیحات و یا اطلاعات بیشتری را نیز توسط پارامترهای خود ارائه دهند.
امکان تهیه سرویسهای سفارشی بررسی سلامت برنامه
در مثال قبل، منطق بررسی سلامت برنامه را همانجا داخل متد ConfigureServices، به کمک متد services.AddHealthChecks().AddCheck معرفی کردیم. امکان انتقال این کدها به سرویسهای سفارشی، با پیاده سازی اینترفیس IHealthCheck نیز وجود دارد:
public class SqlServerHealthCheck : IHealthCheck
{
private readonly IConfiguration _configuration;
public SqlServerHealthCheck(IConfiguration configuration)
{
_configuration = configuration;
}
public Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context, CancellationToken cancellationToken = default(CancellationToken))
{
using (var connection = new SqlConnection(_configuration["connectionString"]))
{
try
{
connection.Open();
}
catch (SqlException)
{
return Task.FromResult(HealthCheckResult.Unhealthy());
}
}
return Task.FromResult(HealthCheckResult.Healthy());
}
}
در اینجا کدهای AddCheck را به متد CheckHealthAsync منتقل کردیم. پس از آن برای معرفی آن به سیستم میتوان از روش زیر استفاده کرد:
namespace MvcHealthCheckTest
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddHealthChecks()
.AddCheck<SqlServerHealthCheck>("sql");
متد AddCheck، کلاس SqlServerHealthCheck را به صورت یک سرویس جدید با طول عمر Transient به سیستم تزریق وابستگیهای NET Core. معرفی میکند (یعنی با هربار درخواست مسیر working/، یک وهلهی جدید از این کلاس ساخته شده و استفاده میشود) که امکان تزریق در سازندهی کلاس آن نیز وجود دارد.
سفارشی سازی خروجی بررسی سلامت برنامهها
تا اینجا از متدهای کلی Unhealthy و Healthy برای بازگشت وضعیت سلامت برنامه استفاده کردیم؛ خروجیهای بهتری را نیز میتوان ارائه داد:
public Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context,
CancellationToken cancellationToken = default(CancellationToken))
{
using (var connection = new SqlConnection(_configuration["connectionString"]))
{
try
{
connection.Open();
}
catch (SqlException)
{
return Task.FromResult(new HealthCheckResult(
status: context.Registration.FailureStatus,
description: "It is dead!"));
}
}
return Task.FromResult(HealthCheckResult.Healthy("Healthy as a horse"));
}
در نهایت نیاز است خروجی از نوع HealthCheckResult بازگشت داده شود. این خروجی را یا میتوان توسط متدهای Healthy و Unhealthy با پارامترهای مخصوص آنها ایجاد کرد و یا مانند این مثال، توسط وهله سازی مستقیم آن.
روش دیگر سفارشی سازی خروجی آن، استفاده از پارامتر دوم متد app.UseHealthChecks است:
namespace MvcHealthCheckTest
{
public class Startup
{
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseHealthChecks("/working", new HealthCheckOptions
{
ResponseWriter = async (context, report) =>
{
var result = JsonConvert.SerializeObject(new
{
status = report.Status.ToString(),
errors = report.Entries.Select(e =>
new
{
key = e.Key,
value = Enum.GetName(typeof(HealthStatus), e.Value.Status)
})
});
context.Response.ContentType = MediaTypeNames.Application.Json;
await context.Response.WriteAsync(result);
}
});
در اینجا یک خروجی JSON، از ریز خطاهای گزارش شده، تهیه شده و توسط context.Response.WriteAsync به فراخوان ارائه میشود.
معرفی کتابخانهای از IHealthCheckهای سفارشی
از مخزن کد
AspNetCore.Diagnostics.HealthChecks میتوانید IHealthCheckهای سفارشی مخصوص SQL Server، MySQL و غیره را نیز دریافت و استفاده کنید.