ASP.NET Core 프로젝트에 상태 확인을 추가하는 방법. 코딩 이야기.

TL;DR



상태 확인은 중요하며 ASP.NET Core에서 사용하는 것이 매우 간단합니다. 다양한 시나리오에서 추가하고 사용하는 방법을 보여주기 위해 코딩 스토리를 만들었습니다. (데이터베이스, rabbitmq, 다운스트림 서비스).


시스템의 관찰 가능성은 성공적인 유지 관리 및 모니터링에 매우 중요합니다. 건강 검진이 도움이 됩니다!

아래에서 ASP.NET Core 프로젝트에 상태 확인 지원을 추가하는 프로세스를 설명하는 코딩 스토리를 찾을 수 있습니다.

https://codingstories.io/story/https:%2F%2Fgitlab.com%2Fcodingstories%2Fhow-to-add-health-checks-to-aspnetcore



결과 미리보기



코딩 스토리가 끝나면 다음과 같은 내용을 볼 수 있습니다.

public class Startup
{
   public IConfiguration Configuration { get; set; }
   public Startup(IConfiguration configuration)
   {
      this.Configuration = configuration;
   }

   public void ConfigureServices(IServiceCollection services)
   {
      var connectionString = this.Configuration.GetConnectionString("DefaultConnection");
      var rabbitMqConnectionString = this.Configuration.GetConnectionString("RabbitMQ");
      var downstreamServiceUrl = this.Configuration["DownstreamService:BaseUrl"];
      services.AddHealthChecks()
            .AddSqlServer(
               connectionString,
               name: "Database",
               failureStatus: HealthStatus.Degraded,
               timeout: TimeSpan.FromSeconds(1),
               tags: new string[] { "services" })
            .AddRabbitMQ(
               rabbitMqConnectionString,
               name: "RabbitMQ",
               failureStatus: HealthStatus.Degraded,
               timeout: TimeSpan.FromSeconds(1),
               tags: new string[] { "services" })
            .AddUrlGroup(
               new Uri($"{downstreamServiceUrl}/health"),
               name: "Downstream API Health Check",
               failureStatus: HealthStatus.Unhealthy,
               timeout: TimeSpan.FromSeconds(3),
               tags: new string[] { "services" });
   }

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

      app.UseEndpoints(endpoints =>
      {
            endpoints.MapCustomHealthCheck();

            endpoints.MapGet("/{**path}", async context =>
            {
               await context.Response.WriteAsync(
                  "Navigate to /health to see the health status.");
            });
      });
   }
}




public static class EndpointRouteBuilderExtensions
{
   /// <summary>
   /// Adds a Health Check endpoint to the <see cref="IEndpointRouteBuilder"/> with the specified template.
   /// </summary>
   /// <param name="endpoints">The <see cref="IEndpointRouteBuilder"/> to add endpoint to.</param>
   /// <param name="pattern">The URL pattern of the liveness endpoint.</param>
   /// <param name="servicesPattern">The URL pattern of the readiness endpoint.</param>
   /// <returns></returns>
   public static IEndpointRouteBuilder MapCustomHealthCheck(
      this IEndpointRouteBuilder endpoints,
      string pattern = "/health",
      string servicesPattern = "/health/ready")
   {
      if (endpoints == null)
      {
            throw new ArgumentNullException(nameof(endpoints));
      }

      endpoints.MapHealthChecks(pattern, new HealthCheckOptions()
      {
            Predicate = (check) => !check.Tags.Contains("services"),
            AllowCachingResponses = false,
            ResponseWriter = WriteResponse,
      });
      endpoints.MapHealthChecks(servicesPattern, new HealthCheckOptions()
      {
            Predicate = (check) => true,
            AllowCachingResponses = false,
            ResponseWriter = WriteResponse,
      });

      return endpoints;
   }

   private static Task WriteResponse(HttpContext context, HealthReport result)
   {
      context.Response.ContentType = "application/json; charset=utf-8";

      var options = new JsonWriterOptions
      {
            Indented = true
      };

      using var stream = new MemoryStream();
      using (var writer = new Utf8JsonWriter(stream, options))
      {
            writer.WriteStartObject();
            writer.WriteString("status", result.Status.ToString());
            writer.WriteStartObject("results");
            foreach (var entry in result.Entries)
            {
               writer.WriteStartObject(entry.Key);
               writer.WriteString("status", entry.Value.Status.ToString());
               writer.WriteEndObject();
            }
            writer.WriteEndObject();
            writer.WriteEndObject();
      }

      var json = Encoding.UTF8.GetString(stream.ToArray());

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



이 코딩 스토리에 대해 어떻게 생각하는지 알려주세요. 피드백은 대단히 감사합니다 👍.

참조


  • https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/health-checks
  • https://gitlab.com/NikiforovAll/how-to-add-health-checks-to-aspnetcore
  • 좋은 웹페이지 즐겨찾기