Use spring-retry for consul config and discovery.
fixes gh-81
This commit is contained in:
@@ -185,6 +185,21 @@ You could store a YAML document in any of the keys listed above.
|
||||
|
||||
You can change the data key using `spring.cloud.consul.config.data-key`.
|
||||
|
||||
[[spring-cloud-consul-retry]]
|
||||
== Consul Retry
|
||||
|
||||
If you expect that the consul agent may occasionally be unavailable when
|
||||
your app starts, you can ask it to keep trying after a failure. You need to add
|
||||
`spring-retry` and `spring-boot-starter-aop` to your classpath. The default
|
||||
behaviour is to retry 6 times with an initial backoff interval of 1000ms and an
|
||||
exponential multiplier of 1.1 for subsequent backoffs. You can configure these
|
||||
properties (and others) using `spring.cloud.consul.retry.*` configuration properties.
|
||||
This works with both Spring Cloud Consul Config and Discovery registration.
|
||||
|
||||
TIP: To take full control of the retry add a `@Bean` of type
|
||||
`RetryOperationsInterceptor` with id "consulRetryInterceptor". Spring
|
||||
Retry has a `RetryInterceptorBuilder` that makes it easy to create one.
|
||||
|
||||
[[spring-cloud-consul-bus]]
|
||||
== Spring Cloud Bus with Consul
|
||||
|
||||
|
||||
@@ -22,6 +22,11 @@
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.retry</groupId>
|
||||
<artifactId>spring-retry</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.ecwid.consul</groupId>
|
||||
<artifactId>consul-api</artifactId>
|
||||
|
||||
@@ -22,16 +22,19 @@ import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.core.env.CompositePropertySource;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@Order(0)
|
||||
public class ConsulPropertySourceLocator implements PropertySourceLocator {
|
||||
|
||||
private ConsulClient consul;
|
||||
@@ -44,6 +47,7 @@ public class ConsulPropertySourceLocator implements PropertySourceLocator {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Retryable(interceptor = "consulRetryInterceptor")
|
||||
public PropertySource<?> locate(Environment environment) {
|
||||
if (environment instanceof ConfigurableEnvironment) {
|
||||
ConfigurableEnvironment env = (ConfigurableEnvironment) environment;
|
||||
|
||||
@@ -32,6 +32,16 @@
|
||||
<artifactId>spring-cloud-commons</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.retry</groupId>
|
||||
<artifactId>spring-retry</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.ecwid.consul</groupId>
|
||||
<artifactId>consul-api</artifactId>
|
||||
|
||||
@@ -18,14 +18,21 @@ package org.springframework.cloud.consul;
|
||||
|
||||
import com.ecwid.consul.v1.ConsulClient;
|
||||
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.actuate.endpoint.Endpoint;
|
||||
import org.springframework.boot.autoconfigure.aop.AopAutoConfiguration;
|
||||
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.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.retry.annotation.EnableRetry;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.retry.interceptor.RetryInterceptorBuilder;
|
||||
import org.springframework.retry.interceptor.RetryOperationsInterceptor;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
@@ -67,4 +74,23 @@ public class ConsulAutoConfiguration {
|
||||
return new ConsulHealthIndicator(consulClient);
|
||||
}
|
||||
}
|
||||
|
||||
@ConditionalOnClass({ Retryable.class, Aspect.class, AopAutoConfiguration.class })
|
||||
@Configuration
|
||||
@EnableRetry(proxyTargetClass = true)
|
||||
@Import(AopAutoConfiguration.class)
|
||||
@EnableConfigurationProperties(RetryProperties.class)
|
||||
protected static class RetryConfiguration {
|
||||
|
||||
@Bean(name = "consulRetryInterceptor")
|
||||
@ConditionalOnMissingBean(name = "consulRetryInterceptor")
|
||||
public RetryOperationsInterceptor consulRetryInterceptor(
|
||||
RetryProperties properties) {
|
||||
return RetryInterceptorBuilder
|
||||
.stateless()
|
||||
.backOffOptions(properties.getInitialInterval(),
|
||||
properties.getMultiplier(), properties.getMaxInterval())
|
||||
.maxAttempts(properties.getMaxAttempts()).build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,12 +28,15 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
@ConfigurationProperties("spring.cloud.consul")
|
||||
@Data
|
||||
public class ConsulProperties {
|
||||
/** Consul agent hostname. Defaults to 'localhost'. */
|
||||
@NotNull
|
||||
private String host = "localhost";
|
||||
|
||||
/** Consul agent port. Defaults to '8500'. */
|
||||
@NotNull
|
||||
private int port = 8500;
|
||||
|
||||
/** Is spring cloud consul enabled */
|
||||
private boolean enabled = true;
|
||||
|
||||
private String prefix = "config";
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright 2013-2016 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.cloud.consul;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author Spencer Gibb
|
||||
*/
|
||||
@ConfigurationProperties("spring.cloud.consul.retry")
|
||||
@Data
|
||||
public class RetryProperties {
|
||||
|
||||
/** Initial retry interval in milliseconds. */
|
||||
private long initialInterval = 1000;
|
||||
|
||||
/** Multiplier for next interval. */
|
||||
private double multiplier = 1.1;
|
||||
|
||||
/** Maximum interval for backoff. */
|
||||
private long maxInterval = 2000;
|
||||
|
||||
/** Maximum number of attempts. */
|
||||
private int maxAttempts = 6;
|
||||
}
|
||||
@@ -125,6 +125,11 @@
|
||||
<artifactId>joda-time</artifactId>
|
||||
<version>${joda-time.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.retry</groupId>
|
||||
<artifactId>spring-retry</artifactId>
|
||||
<version>1.1.2.RELEASE</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-netflix-dependencies</artifactId>
|
||||
|
||||
@@ -82,6 +82,11 @@
|
||||
<artifactId>ribbon-loadbalancer</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.retry</groupId>
|
||||
<artifactId>spring-retry</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
|
||||
@@ -25,6 +25,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cloud.client.discovery.AbstractDiscoveryLifecycle;
|
||||
import org.springframework.retry.annotation.Retryable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -69,6 +70,12 @@ public class ConsulLifecycle extends AbstractDiscoveryLifecycle {
|
||||
service.setPort(port);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Retryable(interceptor = "consulRetryInterceptor")
|
||||
public void start() {
|
||||
super.start();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void register() {
|
||||
Assert.notNull(service.getPort(), "service.port has not been set");
|
||||
|
||||
Reference in New Issue
Block a user