Commit 718bc72f authored by Stephane Nicoll's avatar Stephane Nicoll

Merge pull request #11997 from qinnnyul:add-health-indicator-for-reactive-mongo

* pr/11997:
  Polish "Add health indicator for reactive MongoDB"
  Add health indicator for reactive MongoDB
parents a02fdc75 28f53927
......@@ -248,6 +248,16 @@
<artifactId>liquibase-core</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-async</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-reactivestreams</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
......
......@@ -16,51 +16,32 @@
package org.springframework.boot.actuate.autoconfigure.mongo;
import java.util.Map;
import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthIndicatorConfiguration;
import org.springframework.boot.actuate.autoconfigure.health.ConditionalOnEnabledHealthIndicator;
import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.actuate.mongo.MongoHealthIndicator;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
import org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.context.annotation.Import;
/**
* {@link EnableAutoConfiguration Auto-configuration} for {@link MongoHealthIndicator}.
*
* @author Christian Dupuis
* @author Stephane Nicoll
* @since 2.0.0
*/
@Configuration
@ConditionalOnClass(MongoTemplate.class)
@ConditionalOnBean(MongoTemplate.class)
@ConditionalOnEnabledHealthIndicator("mongo")
@AutoConfigureBefore(HealthIndicatorAutoConfiguration.class)
@AutoConfigureAfter({ MongoAutoConfiguration.class, MongoDataAutoConfiguration.class })
public class MongoHealthIndicatorAutoConfiguration extends
CompositeHealthIndicatorConfiguration<MongoHealthIndicator, MongoTemplate> {
private final Map<String, MongoTemplate> mongoTemplates;
public MongoHealthIndicatorAutoConfiguration(
Map<String, MongoTemplate> mongoTemplates) {
this.mongoTemplates = mongoTemplates;
}
@Bean
@ConditionalOnMissingBean(name = "mongoHealthIndicator")
public HealthIndicator mongoHealthIndicator() {
return createHealthIndicator(this.mongoTemplates);
}
@AutoConfigureAfter({ MongoAutoConfiguration.class, MongoDataAutoConfiguration.class,
MongoReactiveDataAutoConfiguration.class })
@Import({ MongoReactiveHealthIndicatorConfiguration.class,
MongoHealthIndicatorConfiguration.class })
public class MongoHealthIndicatorAutoConfiguration {
}
/*
* Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.mongo;
import java.util.Map;
import org.springframework.boot.actuate.autoconfigure.health.CompositeHealthIndicatorConfiguration;
import org.springframework.boot.actuate.health.HealthIndicator;
import org.springframework.boot.actuate.mongo.MongoHealthIndicator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.MongoTemplate;
/**
* Configuration for {@link MongoHealthIndicator}.
*
* @author Stephane Nicoll
*/
@Configuration
@ConditionalOnClass(MongoTemplate.class)
@ConditionalOnBean(MongoTemplate.class)
class MongoHealthIndicatorConfiguration extends
CompositeHealthIndicatorConfiguration<MongoHealthIndicator, MongoTemplate> {
private final Map<String, MongoTemplate> mongoTemplates;
MongoHealthIndicatorConfiguration(
Map<String, MongoTemplate> mongoTemplates) {
this.mongoTemplates = mongoTemplates;
}
@Bean
@ConditionalOnMissingBean(name = "mongoHealthIndicator")
public HealthIndicator mongoHealthIndicator() {
return createHealthIndicator(this.mongoTemplates);
}
}
/*
* Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.mongo;
import java.util.Map;
import org.springframework.boot.actuate.autoconfigure.health.CompositeReactiveHealthIndicatorConfiguration;
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
import org.springframework.boot.actuate.mongo.MongoReactiveHealthIndicator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
/**
* Configuration for {@link MongoReactiveHealthIndicator}.
*
* @author Stephane Nicoll
*/
@Configuration
@ConditionalOnClass(ReactiveMongoTemplate.class)
@ConditionalOnBean(ReactiveMongoTemplate.class)
class MongoReactiveHealthIndicatorConfiguration extends
CompositeReactiveHealthIndicatorConfiguration<MongoReactiveHealthIndicator, ReactiveMongoTemplate> {
private final Map<String, ReactiveMongoTemplate> reactiveMongoTemplate;
MongoReactiveHealthIndicatorConfiguration(
Map<String, ReactiveMongoTemplate> reactiveMongoTemplate) {
this.reactiveMongoTemplate = reactiveMongoTemplate;
}
@Bean
@ConditionalOnMissingBean(name = "mongoHealthIndicator")
public ReactiveHealthIndicator mongoHealthIndicator() {
return createHealthIndicator(this.reactiveMongoTemplate);
}
}
......@@ -26,6 +26,7 @@ import org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoCo
import org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration;
import org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration;
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
import org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration;
import org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration;
import org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
......@@ -69,10 +70,11 @@ public class SpringApplicationHierarchyTests {
@EnableAutoConfiguration(exclude = { ElasticsearchDataAutoConfiguration.class,
ElasticsearchRepositoriesAutoConfiguration.class,
CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class,
MongoDataAutoConfiguration.class, Neo4jDataAutoConfiguration.class,
Neo4jRepositoriesAutoConfiguration.class, RedisAutoConfiguration.class,
RedisRepositoriesAutoConfiguration.class, FlywayAutoConfiguration.class,
JestAutoConfiguration.class, MetricsAutoConfiguration.class }, excludeName = {
MongoDataAutoConfiguration.class, MongoReactiveDataAutoConfiguration.class,
Neo4jDataAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class,
RedisAutoConfiguration.class, RedisRepositoriesAutoConfiguration.class,
FlywayAutoConfiguration.class, JestAutoConfiguration.class,
MetricsAutoConfiguration.class }, excludeName = {
"org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration" })
public static class Child {
......@@ -81,10 +83,11 @@ public class SpringApplicationHierarchyTests {
@EnableAutoConfiguration(exclude = { ElasticsearchDataAutoConfiguration.class,
ElasticsearchRepositoriesAutoConfiguration.class,
CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class,
MongoDataAutoConfiguration.class, Neo4jDataAutoConfiguration.class,
Neo4jRepositoriesAutoConfiguration.class, RedisAutoConfiguration.class,
RedisRepositoriesAutoConfiguration.class, FlywayAutoConfiguration.class,
JestAutoConfiguration.class, MetricsAutoConfiguration.class }, excludeName = {
MongoDataAutoConfiguration.class, MongoReactiveDataAutoConfiguration.class,
Neo4jDataAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class,
RedisAutoConfiguration.class, RedisRepositoriesAutoConfiguration.class,
FlywayAutoConfiguration.class, JestAutoConfiguration.class,
MetricsAutoConfiguration.class }, excludeName = {
"org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration" })
public static class Parent {
......
......@@ -28,6 +28,7 @@ import org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoCo
import org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration;
import org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration;
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
import org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration;
import org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration;
import org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
......@@ -39,6 +40,7 @@ import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
import org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration;
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration;
import org.springframework.boot.autoconfigure.solr.SolrAutoConfiguration;
import org.springframework.boot.context.annotation.UserConfigurations;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
......@@ -81,8 +83,10 @@ public class WebEndpointsAutoConfigurationIntegrationTests {
LiquibaseAutoConfiguration.class, CassandraAutoConfiguration.class,
CassandraDataAutoConfiguration.class, Neo4jDataAutoConfiguration.class,
Neo4jRepositoriesAutoConfiguration.class, MongoAutoConfiguration.class,
MongoDataAutoConfiguration.class, MongoReactiveAutoConfiguration.class,
MongoReactiveDataAutoConfiguration.class,
RepositoryRestMvcAutoConfiguration.class, HazelcastAutoConfiguration.class,
MongoDataAutoConfiguration.class, ElasticsearchAutoConfiguration.class,
ElasticsearchAutoConfiguration.class,
ElasticsearchDataAutoConfiguration.class, JestAutoConfiguration.class,
SolrRepositoriesAutoConfiguration.class, SolrAutoConfiguration.class,
RedisAutoConfiguration.class, RedisRepositoriesAutoConfiguration.class,
......
/*
* Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.autoconfigure.mongo;
import org.junit.Test;
import org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorAutoConfiguration;
import org.springframework.boot.actuate.health.ApplicationHealthIndicator;
import org.springframework.boot.actuate.mongo.MongoHealthIndicator;
import org.springframework.boot.actuate.mongo.MongoReactiveHealthIndicator;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration;
import org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link MongoReactiveHealthIndicatorConfiguration}.
*
* @author Yulin Qin
*/
public class MongoReactiveHealthIndicatorConfigurationTests {
private ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withConfiguration(AutoConfigurations.of(
MongoAutoConfiguration.class,
MongoDataAutoConfiguration.class,
MongoReactiveAutoConfiguration.class,
MongoReactiveDataAutoConfiguration.class,
MongoHealthIndicatorAutoConfiguration.class,
HealthIndicatorAutoConfiguration.class));
@Test
public void runShouldCreateIndicator() {
this.contextRunner.run(
(context) -> assertThat(context).hasSingleBean(MongoReactiveHealthIndicator.class)
.doesNotHaveBean(MongoHealthIndicator.class)
.doesNotHaveBean(ApplicationHealthIndicator.class));
}
@Test
public void runWhenDisabledShouldNotCreateIndicator() {
this.contextRunner.withPropertyValues("management.health.mongo.enabled:false")
.run((context) -> assertThat(context)
.doesNotHaveBean(MongoReactiveHealthIndicator.class)
.doesNotHaveBean(MongoHealthIndicator.class)
.hasSingleBean(ApplicationHealthIndicator.class));
}
}
......@@ -142,6 +142,16 @@
<artifactId>liquibase-core</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-async</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongodb-driver-reactivestreams</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
......
/*
* Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.mongo;
import org.bson.Document;
import reactor.core.publisher.Mono;
import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.ReactiveHealthIndicator;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import org.springframework.util.Assert;
/**
* A {@link ReactiveHealthIndicator} for Mongo.
*
* @author Yulin Qin
* @since 2.0.0
*/
public class MongoReactiveHealthIndicator extends AbstractReactiveHealthIndicator {
private final ReactiveMongoTemplate reactiveMongoTemplate;
public MongoReactiveHealthIndicator(ReactiveMongoTemplate reactiveMongoTemplate) {
Assert.notNull(reactiveMongoTemplate, "ReactiveMongoTemplate must not be null");
this.reactiveMongoTemplate = reactiveMongoTemplate;
}
@Override
protected Mono<Health> doHealthCheck(Health.Builder builder) {
Mono<Document> buildInfo = this.reactiveMongoTemplate.executeCommand(
"{ buildInfo: 1 }");
return buildInfo.map(document -> up(builder, document));
}
private Health up(Health.Builder builder, Document document) {
return builder.up().withDetail("version", document.getString("version")).build();
}
}
/*
* Copyright 2012-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.actuate.mongo;
import com.mongodb.MongoException;
import org.bson.Document;
import org.junit.Test;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import org.springframework.boot.actuate.health.Health;
import org.springframework.boot.actuate.health.Status;
import org.springframework.data.mongodb.core.ReactiveMongoTemplate;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link MongoReactiveHealthIndicator}.
*
* @author Yulin Qin
*/
public class MongoReactiveHealthIndicatorTest {
@Test
public void testMongoIsUp() {
Document buildInfo = mock(Document.class);
given(buildInfo.getString("version")).willReturn("2.6.4");
ReactiveMongoTemplate reactiveMongoTemplate = mock(ReactiveMongoTemplate.class);
given(reactiveMongoTemplate.executeCommand("{ buildInfo: 1 }")).willReturn(
Mono.just(buildInfo));
MongoReactiveHealthIndicator mongoReactiveHealthIndicator = new MongoReactiveHealthIndicator(reactiveMongoTemplate);
Mono<Health> health = mongoReactiveHealthIndicator.health();
StepVerifier.create(health).consumeNextWith((h) -> {
assertThat(h.getStatus()).isEqualTo(Status.UP);
assertThat(h.getDetails()).containsOnlyKeys("version");
assertThat(h.getDetails().get("version")).isEqualTo("2.6.4");
}).verifyComplete();
}
@Test
public void testMongoIsDown() {
ReactiveMongoTemplate reactiveMongoTemplate = mock(ReactiveMongoTemplate.class);
given(reactiveMongoTemplate.executeCommand("{ buildInfo: 1 }")).willThrow(
new MongoException("Connection failed"));
MongoReactiveHealthIndicator mongoReactiveHealthIndicator = new MongoReactiveHealthIndicator(reactiveMongoTemplate);
Mono<Health> health = mongoReactiveHealthIndicator.health();
StepVerifier.create(health).consumeNextWith((h) -> {
assertThat(h.getStatus()).isEqualTo(Status.DOWN);
assertThat(h.getDetails()).containsOnlyKeys("error");
assertThat(h.getDetails().get("error")).isEqualTo("Connection failed");
}).verifyComplete();
}
}
......@@ -723,6 +723,9 @@ appropriate:
|===
|Name |Description
|{sc-spring-boot-actuator}/mongo/MongoReactiveHealthIndicator.{sc-ext}[`MongoReactiveHealthIndicator`]
|Checks that a Mongo database is up.
|{sc-spring-boot-actuator}/redis/RedisReactiveHealthIndicator.{sc-ext}[`RedisReactiveHealthIndicator`]
|Checks that a Redis server is up.
|===
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment