Skip to content

Commit eee2694

Browse files
qinnnyulsnicoll
authored andcommitted
Add health indicator for reactive MongoDB
See gh-11997
1 parent a02fdc7 commit eee2694

File tree

7 files changed

+273
-2
lines changed

7 files changed

+273
-2
lines changed

spring-boot-project/spring-boot-actuator-autoconfigure/pom.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,16 @@
248248
<artifactId>liquibase-core</artifactId>
249249
<optional>true</optional>
250250
</dependency>
251+
<dependency>
252+
<groupId>org.mongodb</groupId>
253+
<artifactId>mongodb-driver-async</artifactId>
254+
<optional>true</optional>
255+
</dependency>
256+
<dependency>
257+
<groupId>org.mongodb</groupId>
258+
<artifactId>mongodb-driver-reactivestreams</artifactId>
259+
<optional>true</optional>
260+
</dependency>
251261
<dependency>
252262
<groupId>org.springframework</groupId>
253263
<artifactId>spring-jdbc</artifactId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.mongo;
18+
19+
import java.util.Map;
20+
21+
import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthIndicatorConfiguration;
22+
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
23+
import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration;
24+
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
25+
import org.springframework.boot.actuate.mongo.MongoReactiveHealthIndicator;
26+
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
27+
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
28+
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
29+
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
30+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
31+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
32+
import org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration;
33+
import org.springframework.context.annotation.Bean;
34+
import org.springframework.context.annotation.Configuration;
35+
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
36+
37+
38+
39+
/**
40+
* {@link EnableAutoConfiguration Auto-configuration} for {@link MongoReactiveHealthIndicator}.
41+
*
42+
* @author Yulin Qin
43+
* @since 2.0.0
44+
*/
45+
@Configuration
46+
@ConditionalOnClass(ReactiveMongoTemplate.class)
47+
@ConditionalOnBean(ReactiveMongoTemplate.class)
48+
@ConditionalOnEnabledHealthIndicator("mongo")
49+
@AutoConfigureBefore(HealthIndicatorAutoConfiguration.class)
50+
@AutoConfigureAfter(MongoReactiveDataAutoConfiguration.class)
51+
public class MongoReactiveHealthIndicatorAutoConfiguration extends
52+
CompositeReactiveHealthIndicatorConfiguration<MongoReactiveHealthIndicator, ReactiveMongoTemplate> {
53+
54+
private final Map<String, ReactiveMongoTemplate> reactiveMongoTemplate;
55+
56+
public MongoReactiveHealthIndicatorAutoConfiguration(
57+
Map<String, ReactiveMongoTemplate> reactiveMongoTemplate) {
58+
this.reactiveMongoTemplate = reactiveMongoTemplate;
59+
}
60+
61+
@Bean
62+
@ConditionalOnMissingBean(name = "mongoReactiveHealthIndicator")
63+
public ReactiveHealthIndicator mongoReactiveHealthIndicator() {
64+
return createHealthIndicator(this.reactiveMongoTemplate);
65+
}
66+
67+
}

spring-boot-project/spring-boot-actuator-autoconfigure/src/main/resources/META-INF/spring.factories

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ org.springframework.boot.actuate.autoconfigure.metrics.web.client.RestTemplateMe
5353
org.springframework.boot.actuate.autoconfigure.metrics.web.reactive.WebFluxMetricsAutoConfiguration,\
5454
org.springframework.boot.actuate.autoconfigure.metrics.web.servlet.WebMvcMetricsAutoConfiguration,\
5555
org.springframework.boot.actuate.autoconfigure.mongo.MongoHealthIndicatorAutoConfiguration,\
56+
org.springframework.boot.actuate.autoconfigure.mongo.MongoReactiveHealthIndicatorAutoConfiguration,\
5657
org.springframework.boot.actuate.autoconfigure.neo4j.Neo4jHealthIndicatorAutoConfiguration,\
5758
org.springframework.boot.actuate.autoconfigure.redis.RedisHealthIndicatorAutoConfiguration,\
5859
org.springframework.boot.actuate.autoconfigure.scheduling.ScheduledTasksEndpointAutoConfiguration,\
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.autoconfigure.mongo;
18+
19+
import org.junit.Test;
20+
21+
import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration;
22+
import org.springframework.boot.actuate.health.ApplicationHealthIndicator;
23+
import org.springframework.boot.actuate.mongo.MongoHealthIndicator;
24+
import org.springframework.boot.actuate.mongo.MongoReactiveHealthIndicator;
25+
import org.springframework.boot.autoconfigure.AutoConfigurations;
26+
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
27+
import org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration;
28+
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
29+
import org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration;
30+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
31+
32+
import static org.assertj.core.api.Assertions.assertThat;
33+
34+
/**
35+
* Tests for {@link MongoReactiveHealthIndicatorAutoConfiguration}
36+
*
37+
* @author Yulin Qin
38+
*/
39+
public class MongoReactiveHealthIndicatorAutoConfigurationTests {
40+
41+
private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
42+
.withConfiguration(AutoConfigurations.of(
43+
MongoAutoConfiguration.class,
44+
MongoDataAutoConfiguration.class,
45+
MongoReactiveAutoConfiguration.class,
46+
MongoReactiveDataAutoConfiguration.class,
47+
MongoReactiveHealthIndicatorAutoConfiguration.class,
48+
HealthIndicatorAutoConfiguration.class));
49+
50+
@Test
51+
public void runShouldCreateIndicator() {
52+
this.contextRunner.run(
53+
(context) -> assertThat(context).hasSingleBean(MongoReactiveHealthIndicator.class)
54+
.doesNotHaveBean(MongoHealthIndicator.class)
55+
.doesNotHaveBean(ApplicationHealthIndicator.class));
56+
}
57+
58+
@Test
59+
public void runWhenDisabledShouldNotCreateIndicator() {
60+
this.contextRunner.withPropertyValues("management.health.mongo.enabled:false")
61+
.run((context) -> assertThat(context)
62+
.doesNotHaveBean(MongoReactiveHealthIndicator.class)
63+
.doesNotHaveBean(MongoHealthIndicator.class)
64+
.hasSingleBean(ApplicationHealthIndicator.class));
65+
}
66+
67+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.mongo;
18+
19+
import org.bson.Document;
20+
import reactor.core.publisher.Mono;
21+
22+
import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator;
23+
import org.springframework.boot.actuate.health.Health;
24+
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
25+
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
26+
import org.springframework.util.Assert;
27+
28+
29+
30+
/**
31+
* A {@link ReactiveHealthIndicator} for Mongo.
32+
*
33+
* @author Yulin Qin
34+
* @since 2.0.0
35+
*/
36+
public class MongoReactiveHealthIndicator extends AbstractReactiveHealthIndicator {
37+
38+
private final ReactiveMongoTemplate reactiveMongoTemplate;
39+
40+
public MongoReactiveHealthIndicator(ReactiveMongoTemplate reactiveMongoTemplate) {
41+
Assert.notNull(reactiveMongoTemplate, "ReactiveMongoTemplate must not be null");
42+
this.reactiveMongoTemplate = reactiveMongoTemplate;
43+
}
44+
45+
@Override
46+
protected Mono<Health> doHealthCheck(Health.Builder builder) {
47+
Mono<Document> documentMono = this.reactiveMongoTemplate.executeCommand("{ buildInfo: 1 }");
48+
return documentMono.map(document -> up(builder, document));
49+
}
50+
51+
private Health up(Health.Builder builder, Document document) {
52+
return builder.up().withDetail("version", document.getString("version")).build();
53+
}
54+
}
55+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.actuate.mongo;
18+
19+
import com.mongodb.MongoException;
20+
import org.bson.Document;
21+
import org.junit.Test;
22+
import reactor.core.publisher.Mono;
23+
import reactor.test.StepVerifier;
24+
25+
import org.springframework.boot.actuate.health.Health;
26+
import org.springframework.boot.actuate.health.Status;
27+
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
28+
29+
import static org.assertj.core.api.Assertions.assertThat;
30+
import static org.mockito.BDDMockito.given;
31+
import static org.mockito.Mockito.mock;
32+
33+
/**
34+
* Tests for {@link MongoReactiveHealthIndicator}.
35+
*
36+
* @author Yulin Qin
37+
*/
38+
public class MongoReactiveHealthIndicatorTest {
39+
40+
@Test
41+
public void testMongoIsUp() throws Exception {
42+
Document document = mock(Document.class);
43+
ReactiveMongoTemplate reactiveMongoTemplate = mock(ReactiveMongoTemplate.class);
44+
given(reactiveMongoTemplate.executeCommand("{ buildInfo: 1 }")).willReturn(Mono.just(document));
45+
given(document.getString("version")).willReturn("2.6.4");
46+
47+
MongoReactiveHealthIndicator mongoReactiveHealthIndicator = new MongoReactiveHealthIndicator(reactiveMongoTemplate);
48+
Mono<Health> health = mongoReactiveHealthIndicator.health();
49+
StepVerifier.create(health).consumeNextWith((h) -> {
50+
assertThat(h.getStatus()).isEqualTo(Status.UP);
51+
assertThat(h.getDetails()).containsOnlyKeys("version");
52+
assertThat(h.getDetails().get("version")).isEqualTo("2.6.4");
53+
}).verifyComplete();
54+
}
55+
56+
@Test
57+
public void testMongoIsDown() throws Exception {
58+
ReactiveMongoTemplate reactiveMongoTemplate = mock(ReactiveMongoTemplate.class);
59+
given(reactiveMongoTemplate.executeCommand("{ buildInfo: 1 }")).willThrow(new MongoException("Connection failed"));
60+
61+
MongoReactiveHealthIndicator mongoReactiveHealthIndicator = new MongoReactiveHealthIndicator(reactiveMongoTemplate);
62+
Mono<Health> health = mongoReactiveHealthIndicator.health();
63+
StepVerifier.create(health).consumeNextWith((h) -> {
64+
assertThat(h.getStatus()).isEqualTo(Status.DOWN);
65+
assertThat(h.getDetails()).containsOnlyKeys("error");
66+
assertThat(h.getDetails().get("error")).isEqualTo("Connection failed");
67+
}).verifyComplete();
68+
69+
}
70+
}

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoReactiveDataAutoConfiguration.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2018 the original author or authors.
2+
* Copyright 2012-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@
3232
import org.springframework.data.mongodb.core.SimpleReactiveMongoDatabaseFactory;
3333
import org.springframework.data.mongodb.core.convert.MongoConverter;
3434

35+
3536
/**
3637
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data's reactive mongo
3738
* support.
@@ -43,6 +44,7 @@
4344
* to the {@literal test} database.
4445
*
4546
* @author Mark Paluch
47+
* @author Yulin Qin
4648
* @since 2.0.0
4749
*/
4850
@Configuration
@@ -73,5 +75,4 @@ public ReactiveMongoTemplate reactiveMongoTemplate(
7375
MongoConverter converter) {
7476
return new ReactiveMongoTemplate(reactiveMongoDatabaseFactory, converter);
7577
}
76-
7778
}

0 commit comments

Comments
 (0)