Add configurable timeout for Couchbase health indicator
This commit makes sure to use a configurable timeout to check if the Couchbase cluster is up, rather than relying on the default that can be quite long. Closes gh-13879
This commit is contained in:
parent
21691f0b20
commit
a023bd030a
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* 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.
|
||||
|
|
@ -32,6 +32,7 @@ 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.couchbase.CouchbaseDataAutoConfiguration;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.couchbase.core.CouchbaseOperations;
|
||||
|
|
@ -41,6 +42,7 @@ import org.springframework.data.couchbase.core.CouchbaseOperations;
|
|||
* {@link CouchbaseHealthIndicator}.
|
||||
*
|
||||
* @author Eddú Meléndez
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.0
|
||||
*/
|
||||
@Configuration
|
||||
|
|
@ -49,14 +51,19 @@ import org.springframework.data.couchbase.core.CouchbaseOperations;
|
|||
@ConditionalOnEnabledHealthIndicator("couchbase")
|
||||
@AutoConfigureBefore(HealthIndicatorAutoConfiguration.class)
|
||||
@AutoConfigureAfter(CouchbaseDataAutoConfiguration.class)
|
||||
@EnableConfigurationProperties(CouchbaseHealthIndicatorProperties.class)
|
||||
public class CouchbaseHealthIndicatorAutoConfiguration extends
|
||||
CompositeHealthIndicatorConfiguration<CouchbaseHealthIndicator, CouchbaseOperations> {
|
||||
|
||||
private final Map<String, CouchbaseOperations> couchbaseOperations;
|
||||
|
||||
private final CouchbaseHealthIndicatorProperties properties;
|
||||
|
||||
public CouchbaseHealthIndicatorAutoConfiguration(
|
||||
Map<String, CouchbaseOperations> couchbaseOperations) {
|
||||
Map<String, CouchbaseOperations> couchbaseOperations,
|
||||
CouchbaseHealthIndicatorProperties properties) {
|
||||
this.couchbaseOperations = couchbaseOperations;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
|
@ -65,4 +72,11 @@ public class CouchbaseHealthIndicatorAutoConfiguration extends
|
|||
return createHealthIndicator(this.couchbaseOperations);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CouchbaseHealthIndicator createHealthIndicator(
|
||||
CouchbaseOperations couchbaseOperations) {
|
||||
return new CouchbaseHealthIndicator(couchbaseOperations,
|
||||
this.properties.getTimeout());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* 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.couchbase;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
import org.springframework.boot.actuate.couchbase.CouchbaseHealthIndicator;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Configuration properties for {@link CouchbaseHealthIndicator}.
|
||||
*
|
||||
* @author Stephane Nicoll
|
||||
* @since 2.0.5
|
||||
*/
|
||||
@ConfigurationProperties(prefix = "management.health.couchbase")
|
||||
public class CouchbaseHealthIndicatorProperties {
|
||||
|
||||
/**
|
||||
* Timeout for getting the Bucket information from the server.
|
||||
*/
|
||||
private Duration timeout = Duration.ofMillis(1000);
|
||||
|
||||
public Duration getTimeout() {
|
||||
return this.timeout;
|
||||
}
|
||||
|
||||
public void setTimeout(Duration timeout) {
|
||||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* 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.
|
||||
|
|
@ -27,6 +27,7 @@ import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
|||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.couchbase.core.CouchbaseOperations;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
|
@ -35,6 +36,7 @@ import static org.mockito.Mockito.mock;
|
|||
* Tests for {@link CouchbaseHealthIndicatorAutoConfiguration}.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Stephane Nicoll
|
||||
*/
|
||||
public class CouchbaseHealthIndicatorAutoConfigurationTests {
|
||||
|
||||
|
|
@ -50,6 +52,17 @@ public class CouchbaseHealthIndicatorAutoConfigurationTests {
|
|||
.doesNotHaveBean(ApplicationHealthIndicator.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void runWithCustomTimeoutShouldCreateIndicator() {
|
||||
this.contextRunner.withPropertyValues("management.health.couchbase.timeout=2s")
|
||||
.run((context) -> {
|
||||
assertThat(context).hasSingleBean(CouchbaseHealthIndicator.class);
|
||||
assertThat(ReflectionTestUtils.getField(
|
||||
context.getBean(CouchbaseHealthIndicator.class), "timeout"))
|
||||
.isEqualTo(2000L);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void runWhenDisabledShouldNotCreateIndicator() {
|
||||
this.contextRunner.withPropertyValues("management.health.couchbase.enabled:false")
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@
|
|||
|
||||
package org.springframework.boot.actuate.couchbase;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import com.couchbase.client.java.bucket.BucketInfo;
|
||||
import com.couchbase.client.java.cluster.ClusterInfo;
|
||||
|
||||
|
|
@ -35,26 +39,57 @@ import org.springframework.util.StringUtils;
|
|||
*/
|
||||
public class CouchbaseHealthIndicator extends AbstractHealthIndicator {
|
||||
|
||||
private CouchbaseOperations operations;
|
||||
private final CouchbaseOperations operations;
|
||||
|
||||
public CouchbaseHealthIndicator() {
|
||||
super("Couchbase health check failed");
|
||||
}
|
||||
private final long timeout;
|
||||
|
||||
public CouchbaseHealthIndicator(CouchbaseOperations couchbaseOperations) {
|
||||
/**
|
||||
* Create an indicator with the specified {@link CouchbaseOperations} and
|
||||
* {@code timeout}.
|
||||
* @param couchbaseOperations the couchbase operations
|
||||
* @param timeout the request timeout
|
||||
*/
|
||||
public CouchbaseHealthIndicator(CouchbaseOperations couchbaseOperations,
|
||||
Duration timeout) {
|
||||
super("Couchbase health check failed");
|
||||
Assert.notNull(couchbaseOperations, "CouchbaseOperations must not be null");
|
||||
Assert.notNull(timeout, "Timeout must not be null");
|
||||
this.operations = couchbaseOperations;
|
||||
this.timeout = timeout.toMillis();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an indicator with the specified {@link CouchbaseOperations}.
|
||||
* @param couchbaseOperations the couchbase operations
|
||||
* @deprecated as of 2.0.5 in favour of
|
||||
* {@link #CouchbaseHealthIndicator(CouchbaseOperations, Duration)}
|
||||
*/
|
||||
@Deprecated
|
||||
public CouchbaseHealthIndicator(CouchbaseOperations couchbaseOperations) {
|
||||
this(couchbaseOperations, Duration.ofSeconds(1));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doHealthCheck(Health.Builder builder) throws Exception {
|
||||
ClusterInfo cluster = this.operations.getCouchbaseClusterInfo();
|
||||
BucketInfo bucket = this.operations.getCouchbaseBucket().bucketManager().info();
|
||||
BucketInfo bucket = getBucketInfo();
|
||||
String versions = StringUtils
|
||||
.collectionToCommaDelimitedString(cluster.getAllVersions());
|
||||
String nodes = StringUtils.collectionToCommaDelimitedString(bucket.nodeList());
|
||||
builder.up().withDetail("versions", versions).withDetail("nodes", nodes);
|
||||
}
|
||||
|
||||
private BucketInfo getBucketInfo() throws Exception {
|
||||
try {
|
||||
return this.operations.getCouchbaseBucket().bucketManager().info(this.timeout,
|
||||
TimeUnit.MILLISECONDS);
|
||||
}
|
||||
catch (RuntimeException ex) {
|
||||
if (ex.getCause() instanceof TimeoutException) {
|
||||
throw (TimeoutException) ex.getCause();
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2012-2017 the original author or authors.
|
||||
* 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.
|
||||
|
|
@ -18,7 +18,10 @@ package org.springframework.boot.actuate.couchbase;
|
|||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.time.Duration;
|
||||
import java.util.Collections;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import com.couchbase.client.java.Bucket;
|
||||
import com.couchbase.client.java.bucket.BucketInfo;
|
||||
|
|
@ -51,7 +54,7 @@ public class CouchbaseHealthIndicatorTests {
|
|||
given(bucketInfo.nodeList()).willReturn(
|
||||
Collections.singletonList(InetAddress.getByName("127.0.0.1")));
|
||||
BucketManager bucketManager = mock(BucketManager.class);
|
||||
given(bucketManager.info()).willReturn(bucketInfo);
|
||||
given(bucketManager.info(2000, TimeUnit.MILLISECONDS)).willReturn(bucketInfo);
|
||||
Bucket bucket = mock(Bucket.class);
|
||||
given(bucket.bucketManager()).willReturn(bucketManager);
|
||||
ClusterInfo clusterInfo = mock(ClusterInfo.class);
|
||||
|
|
@ -61,7 +64,7 @@ public class CouchbaseHealthIndicatorTests {
|
|||
given(couchbaseOperations.getCouchbaseBucket()).willReturn(bucket);
|
||||
given(couchbaseOperations.getCouchbaseClusterInfo()).willReturn(clusterInfo);
|
||||
CouchbaseHealthIndicator healthIndicator = new CouchbaseHealthIndicator(
|
||||
couchbaseOperations);
|
||||
couchbaseOperations, Duration.ofSeconds(2));
|
||||
Health health = healthIndicator.health();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.UP);
|
||||
assertThat(health.getDetails()).containsOnly(entry("versions", "1.2.3"),
|
||||
|
|
@ -70,13 +73,29 @@ public class CouchbaseHealthIndicatorTests {
|
|||
verify(bucketInfo).nodeList();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void couchbaseTimeout() {
|
||||
BucketManager bucketManager = mock(BucketManager.class);
|
||||
given(bucketManager.info(1500, TimeUnit.MILLISECONDS)).willThrow(
|
||||
new RuntimeException(new TimeoutException("timeout, expected")));
|
||||
Bucket bucket = mock(Bucket.class);
|
||||
given(bucket.bucketManager()).willReturn(bucketManager);
|
||||
CouchbaseOperations couchbaseOperations = mock(CouchbaseOperations.class);
|
||||
given(couchbaseOperations.getCouchbaseBucket()).willReturn(bucket);
|
||||
CouchbaseHealthIndicator healthIndicator = new CouchbaseHealthIndicator(
|
||||
couchbaseOperations, Duration.ofMillis(1500));
|
||||
Health health = healthIndicator.health();
|
||||
assertThat((String) health.getDetails().get("error"))
|
||||
.contains("timeout, expected");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void couchbaseIsDown() {
|
||||
CouchbaseOperations couchbaseOperations = mock(CouchbaseOperations.class);
|
||||
given(couchbaseOperations.getCouchbaseClusterInfo())
|
||||
.willThrow(new IllegalStateException("test, expected"));
|
||||
CouchbaseHealthIndicator healthIndicator = new CouchbaseHealthIndicator(
|
||||
couchbaseOperations);
|
||||
couchbaseOperations, Duration.ofSeconds(1));
|
||||
Health health = healthIndicator.health();
|
||||
assertThat(health.getStatus()).isEqualTo(Status.DOWN);
|
||||
assertThat((String) health.getDetails().get("error")).contains("test, expected");
|
||||
|
|
|
|||
|
|
@ -1276,6 +1276,7 @@ content into your application. Rather, pick only the properties that you need.
|
|||
management.health.db.enabled=true # Whether to enable database health check.
|
||||
management.health.cassandra.enabled=true # Whether to enable Cassandra health check.
|
||||
management.health.couchbase.enabled=true # Whether to enable Couchbase health check.
|
||||
management.health.couchbase.timeout=1000ms # Timeout for getting the Bucket information from the server.
|
||||
management.health.defaults.enabled=true # Whether to enable default health indicators.
|
||||
management.health.diskspace.enabled=true # Whether to enable disk space health check.
|
||||
management.health.diskspace.path= # Path used to compute the available disk space.
|
||||
|
|
|
|||
Loading…
Reference in New Issue