diff --git a/src/Common/src/Common/HealthChecks/HealthAggregator.cs b/src/Common/src/Common/HealthChecks/HealthAggregator.cs index 972837e11d..076928ed0b 100644 --- a/src/Common/src/Common/HealthChecks/HealthAggregator.cs +++ b/src/Common/src/Common/HealthChecks/HealthAggregator.cs @@ -68,7 +68,10 @@ await Parallel.ForEachAsync(contributors, cancellationToken, async (contributor, private static async Task> AggregateMicrosoftHealthChecksAsync(ICollection contributors, ICollection healthCheckRegistrations, IServiceProvider serviceProvider, CancellationToken cancellationToken) { - if (healthCheckRegistrations.Count == 0) + HealthCheckRegistration[] activeHealthCheckRegistrations = + healthCheckRegistrations.Where(registration => !registration.Tags.Contains("ExcludeFromHealthActuator")).ToArray(); + + if (activeHealthCheckRegistrations.Length == 0) { return new Dictionary(); } @@ -76,8 +79,7 @@ private static async Task> Aggreg var healthChecks = new ConcurrentDictionary(); var keys = new ConcurrentBag(contributors.Select(contributor => contributor.Id)); - // run all HealthCheckRegistration checks in parallel - await Parallel.ForEachAsync(healthCheckRegistrations, cancellationToken, async (registration, _) => + await Parallel.ForEachAsync(activeHealthCheckRegistrations, cancellationToken, async (registration, _) => { string contributorName = GetKey(keys, registration.Name); SteeltoeHealthCheckResult healthCheckResult; diff --git a/src/Management/test/Endpoint.Test/Actuators/Health/HealthAggregationTest.cs b/src/Management/test/Endpoint.Test/Actuators/Health/HealthAggregationTest.cs index 216764db61..ad76b9eaad 100644 --- a/src/Management/test/Endpoint.Test/Actuators/Health/HealthAggregationTest.cs +++ b/src/Management/test/Endpoint.Test/Actuators/Health/HealthAggregationTest.cs @@ -517,6 +517,53 @@ public async Task Converts_AspNet_health_check_results() """); } + [Fact] + public async Task Can_skip_AspNet_health_check() + { + WebApplicationBuilder builder = TestWebApplicationBuilderFactory.Create(); + builder.Configuration.AddInMemoryCollection(AppSettings); + builder.Services.AddHealthActuator(); + + IHealthChecksBuilder checksBuilder = builder.Services.AddHealthChecks(); + checksBuilder.AddCheck("aspnet-unhealthy-check", tags: ["ExcludeFromHealthActuator"]); + checksBuilder.AddCheck("aspnet-healthy-check"); + + await using WebApplication host = builder.Build(); + + host.MapHealthChecks("/health"); + await host.StartAsync(TestContext.Current.CancellationToken); + using HttpClient httpClient = host.GetTestClient(); + + HttpResponseMessage actuatorResponse = await httpClient.GetAsync(new Uri("http://localhost/actuator/health"), TestContext.Current.CancellationToken); + + actuatorResponse.StatusCode.Should().Be(HttpStatusCode.OK); + + string actuatorResponseBody = await actuatorResponse.Content.ReadAsStringAsync(TestContext.Current.CancellationToken); + + actuatorResponseBody.Should().BeJson(""" + { + "status": "UP", + "components": { + "aspnet-healthy-check": { + "status": "UP", + "description": "healthy-description", + "details": { + "healthy-data-key": "healthy-data-value" + } + } + } + } + """); + + HttpResponseMessage aspNetResponse = await httpClient.GetAsync(new Uri("http://localhost/health"), TestContext.Current.CancellationToken); + + aspNetResponse.StatusCode.Should().Be(HttpStatusCode.ServiceUnavailable); + + string aspNetResponseBody = await aspNetResponse.Content.ReadAsStringAsync(TestContext.Current.CancellationToken); + + aspNetResponseBody.Should().Be("Unhealthy"); + } + [Fact] public async Task Can_use_scoped_AspNet_health_check() {