mirror of
https://github.com/spring-projects/spring-boot.git
synced 2026-09-27 04:19:03 +00:00
Consider reactive indicators in HealthEndpointGroupMembershipValidator
Update `HealthEndpointGroupMembershipValidator` to also consider reactive health indicators. Fixes gh-48387
This commit is contained in:
+29
-7
@@ -17,6 +17,7 @@
|
||||
package org.springframework.boot.health.autoconfigure.actuate.endpoint;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
@@ -34,6 +35,7 @@ import org.springframework.boot.health.actuate.endpoint.SimpleHttpCodeStatusMapp
|
||||
import org.springframework.boot.health.actuate.endpoint.SimpleStatusAggregator;
|
||||
import org.springframework.boot.health.actuate.endpoint.StatusAggregator;
|
||||
import org.springframework.boot.health.contributor.HealthContributors;
|
||||
import org.springframework.boot.health.contributor.ReactiveHealthContributors;
|
||||
import org.springframework.boot.health.registry.HealthContributorRegistry;
|
||||
import org.springframework.boot.health.registry.ReactiveHealthContributorRegistry;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -78,8 +80,10 @@ class HealthEndpointConfiguration {
|
||||
@Bean
|
||||
@ConditionalOnBooleanProperty(name = "management.endpoint.health.validate-group-membership", matchIfMissing = true)
|
||||
HealthEndpointGroupMembershipValidator healthEndpointGroupMembershipValidator(HealthEndpointProperties properties,
|
||||
HealthContributorRegistry healthContributorRegistry) {
|
||||
return new HealthEndpointGroupMembershipValidator(properties, healthContributorRegistry);
|
||||
HealthContributorRegistry healthContributorRegistry,
|
||||
ObjectProvider<ReactiveHealthContributorRegistry> reactiveHealthContributorRegistry) {
|
||||
return new HealthEndpointGroupMembershipValidator(properties, healthContributorRegistry,
|
||||
reactiveHealthContributorRegistry.getIfAvailable());
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -138,10 +142,13 @@ class HealthEndpointConfiguration {
|
||||
|
||||
private final HealthContributorRegistry registry;
|
||||
|
||||
HealthEndpointGroupMembershipValidator(HealthEndpointProperties properties,
|
||||
HealthContributorRegistry registry) {
|
||||
@Nullable ReactiveHealthContributorRegistry fallbackRegistry;
|
||||
|
||||
HealthEndpointGroupMembershipValidator(HealthEndpointProperties properties, HealthContributorRegistry registry,
|
||||
@Nullable ReactiveHealthContributorRegistry fallbackRegistry) {
|
||||
this.properties = properties;
|
||||
this.registry = registry;
|
||||
this.fallbackRegistry = fallbackRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -172,13 +179,28 @@ class HealthEndpointConfiguration {
|
||||
}
|
||||
|
||||
private boolean contributorExists(String[] path) {
|
||||
return contributorExistsInMainRegistry(path) || contributorExistsInFallbackRegistry(path);
|
||||
}
|
||||
|
||||
private boolean contributorExistsInMainRegistry(String[] path) {
|
||||
return contributorExists(path, this.registry, HealthContributors.class, HealthContributors::getContributor);
|
||||
}
|
||||
|
||||
private boolean contributorExistsInFallbackRegistry(String[] path) {
|
||||
return contributorExists(path, this.fallbackRegistry, ReactiveHealthContributors.class,
|
||||
ReactiveHealthContributors::getContributor);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <C> boolean contributorExists(String[] path, @Nullable Object registry, Class<C> collectionType,
|
||||
BiFunction<C, String, Object> getFromCollection) {
|
||||
int pathOffset = 0;
|
||||
Object contributor = this.registry;
|
||||
Object contributor = registry;
|
||||
while (pathOffset < path.length) {
|
||||
if (!(contributor instanceof HealthContributors)) {
|
||||
if (contributor == null || !collectionType.isInstance(contributor)) {
|
||||
return false;
|
||||
}
|
||||
contributor = ((HealthContributors) contributor).getContributor(path[pathOffset]);
|
||||
contributor = getFromCollection.apply((C) contributor, path[pathOffset]);
|
||||
pathOffset++;
|
||||
}
|
||||
return (contributor != null);
|
||||
|
||||
+36
-2
@@ -44,6 +44,7 @@ import org.springframework.boot.health.autoconfigure.actuate.endpoint.HealthEndp
|
||||
import org.springframework.boot.health.autoconfigure.contributor.HealthContributorAutoConfiguration;
|
||||
import org.springframework.boot.health.autoconfigure.registry.HealthContributorRegistryAutoConfiguration;
|
||||
import org.springframework.boot.health.contributor.CompositeHealthContributor;
|
||||
import org.springframework.boot.health.contributor.CompositeReactiveHealthContributor;
|
||||
import org.springframework.boot.health.contributor.Health;
|
||||
import org.springframework.boot.health.contributor.HealthContributors;
|
||||
import org.springframework.boot.health.contributor.HealthIndicator;
|
||||
@@ -145,6 +146,20 @@ class HealthEndpointAutoConfigurationTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void runDoesNotFailWhenHealthEndpointGroupIncludesContributorThatExists() {
|
||||
this.contextRunner.withUserConfiguration(CompositeHealthIndicatorConfiguration.class)
|
||||
.withPropertyValues("management.endpoint.health.group.ready.include=composite/b/c")
|
||||
.run((context) -> assertThat(context).hasNotFailed());
|
||||
}
|
||||
|
||||
@Test // gh-48387
|
||||
void runDoesNotFailWhenHealthEndpointGroupIncludesReactiveContributorThatExists() {
|
||||
this.contextRunner.withUserConfiguration(CompositeReactiveHealthIndicatorConfiguration.class)
|
||||
.withPropertyValues("management.endpoint.health.group.ready.include=composite/b/c")
|
||||
.run((context) -> assertThat(context).hasNotFailed());
|
||||
}
|
||||
|
||||
@Test
|
||||
void runFailsWhenHealthEndpointGroupIncludesContributorThatDoesNotExist() {
|
||||
this.contextRunner.withUserConfiguration(CompositeHealthIndicatorConfiguration.class)
|
||||
@@ -377,8 +392,27 @@ class HealthEndpointAutoConfigurationTests {
|
||||
|
||||
@Bean
|
||||
CompositeHealthContributor compositeHealthIndicator() {
|
||||
return CompositeHealthContributor.fromMap(Map.of("a", (HealthIndicator) () -> Health.up().build(), "b",
|
||||
CompositeHealthContributor.fromMap(Map.of("c", (HealthIndicator) () -> Health.up().build()))));
|
||||
return CompositeHealthContributor.fromMap(Map.of("a", createHealthIndicator(), "b",
|
||||
CompositeHealthContributor.fromMap(Map.of("c", createHealthIndicator()))));
|
||||
}
|
||||
|
||||
private HealthIndicator createHealthIndicator() {
|
||||
return () -> Health.up().build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class CompositeReactiveHealthIndicatorConfiguration {
|
||||
|
||||
@Bean
|
||||
CompositeReactiveHealthContributor compositeHealthIndicator() {
|
||||
return CompositeReactiveHealthContributor.fromMap(Map.of("a", createHealthIndicator(), "b",
|
||||
CompositeReactiveHealthContributor.fromMap(Map.of("c", createHealthIndicator()))));
|
||||
}
|
||||
|
||||
private ReactiveHealthIndicator createHealthIndicator() {
|
||||
return () -> Mono.just(Health.up().build());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user