Merge branch 'master' into 2.0.x
This commit is contained in:
@@ -405,6 +405,26 @@ The properties you can use are `client.ribbon.MaxAutoRetries`,
|
||||
See the https://github.com/Netflix/ribbon/wiki/Getting-Started#the-properties-file-sample-clientproperties[Ribbon documentation]
|
||||
for a description of what there properties do.
|
||||
|
||||
If you would like to implement a `BackOffPolicy` in your retries you will need to
|
||||
create a bean of type `LoadBalancedBackOffPolicyFactory`, and return the `BackOffPolicy`
|
||||
you would like to use for a given service.
|
||||
|
||||
[source,java,indent=0]
|
||||
----
|
||||
@Configuration
|
||||
public class MyConfiguration {
|
||||
@Bean
|
||||
LoadBalancedBackOffPolicyFactory backOffPolciyFactory() {
|
||||
return new LoadBalancedBackOffPolicyFactory() {
|
||||
@Override
|
||||
public BackOffPolicy createBackOffPolicy(String service) {
|
||||
return new ExponentialBackOffPolicy();
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
----
|
||||
|
||||
NOTE: `client` in the above examples should be replaced with your Ribbon client's
|
||||
name.
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package org.springframework.cloud.client.loadbalancer;
|
||||
|
||||
import org.springframework.retry.backoff.BackOffPolicy;
|
||||
import org.springframework.retry.backoff.NoBackOffPolicy;
|
||||
|
||||
/**
|
||||
* Factory class to return the backoff policy.
|
||||
* @author Ryan Baxter
|
||||
*/
|
||||
public interface LoadBalancedBackOffPolicyFactory {
|
||||
|
||||
public BackOffPolicy createBackOffPolicy(String service);
|
||||
|
||||
static class NoBackOffPolicyFactory implements LoadBalancedBackOffPolicyFactory {
|
||||
|
||||
@Override
|
||||
public BackOffPolicy createBackOffPolicy(String service) {
|
||||
return new NoBackOffPolicy();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -116,6 +116,12 @@ public class LoadBalancerAutoConfiguration {
|
||||
public LoadBalancedRetryPolicyFactory loadBalancedRetryPolicyFactory() {
|
||||
return new LoadBalancedRetryPolicyFactory.NeverRetryFactory();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public LoadBalancedBackOffPolicyFactory loadBalancedBackOffPolicyFactory() {
|
||||
return new LoadBalancedBackOffPolicyFactory.NoBackOffPolicyFactory();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@@ -126,9 +132,10 @@ public class LoadBalancerAutoConfiguration {
|
||||
public RetryLoadBalancerInterceptor ribbonInterceptor(
|
||||
LoadBalancerClient loadBalancerClient, LoadBalancerRetryProperties properties,
|
||||
LoadBalancedRetryPolicyFactory lbRetryPolicyFactory,
|
||||
LoadBalancerRequestFactory requestFactory) {
|
||||
LoadBalancerRequestFactory requestFactory,
|
||||
LoadBalancedBackOffPolicyFactory backOffPolicyFactory) {
|
||||
return new RetryLoadBalancerInterceptor(loadBalancerClient, properties,
|
||||
lbRetryPolicyFactory, requestFactory);
|
||||
lbRetryPolicyFactory, requestFactory, backOffPolicyFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -26,6 +26,8 @@ import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.retry.RetryCallback;
|
||||
import org.springframework.retry.RetryContext;
|
||||
import org.springframework.retry.backoff.BackOffPolicy;
|
||||
import org.springframework.retry.backoff.NoBackOffPolicy;
|
||||
import org.springframework.retry.policy.NeverRetryPolicy;
|
||||
import org.springframework.retry.support.RetryTemplate;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -41,8 +43,11 @@ public class RetryLoadBalancerInterceptor implements ClientHttpRequestIntercepto
|
||||
private LoadBalancerClient loadBalancer;
|
||||
private LoadBalancerRetryProperties lbProperties;
|
||||
private LoadBalancerRequestFactory requestFactory;
|
||||
private LoadBalancedBackOffPolicyFactory backOffPolicyFactory;
|
||||
|
||||
|
||||
@Deprecated
|
||||
//TODO remove in 2.0.x
|
||||
public RetryLoadBalancerInterceptor(LoadBalancerClient loadBalancer,
|
||||
LoadBalancerRetryProperties lbProperties,
|
||||
LoadBalancedRetryPolicyFactory lbRetryPolicyFactory,
|
||||
@@ -51,6 +56,19 @@ public class RetryLoadBalancerInterceptor implements ClientHttpRequestIntercepto
|
||||
this.lbRetryPolicyFactory = lbRetryPolicyFactory;
|
||||
this.lbProperties = lbProperties;
|
||||
this.requestFactory = requestFactory;
|
||||
this.backOffPolicyFactory = new LoadBalancedBackOffPolicyFactory.NoBackOffPolicyFactory();
|
||||
}
|
||||
|
||||
public RetryLoadBalancerInterceptor(LoadBalancerClient loadBalancer,
|
||||
LoadBalancerRetryProperties lbProperties,
|
||||
LoadBalancedRetryPolicyFactory lbRetryPolicyFactory,
|
||||
LoadBalancerRequestFactory requestFactory,
|
||||
LoadBalancedBackOffPolicyFactory backOffPolicyFactory) {
|
||||
this.loadBalancer = loadBalancer;
|
||||
this.lbRetryPolicyFactory = lbRetryPolicyFactory;
|
||||
this.lbProperties = lbProperties;
|
||||
this.requestFactory = requestFactory;
|
||||
this.backOffPolicyFactory = backOffPolicyFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -62,6 +80,8 @@ public class RetryLoadBalancerInterceptor implements ClientHttpRequestIntercepto
|
||||
final LoadBalancedRetryPolicy retryPolicy = lbRetryPolicyFactory.create(serviceName,
|
||||
loadBalancer);
|
||||
RetryTemplate template = this.retryTemplate == null ? new RetryTemplate() : this.retryTemplate;
|
||||
BackOffPolicy backOffPolicy = backOffPolicyFactory.createBackOffPolicy(serviceName);
|
||||
template.setBackOffPolicy(backOffPolicy == null ? new NoBackOffPolicy() : backOffPolicy);
|
||||
template.setThrowLastExceptionOnExhausted(true);
|
||||
template.setRetryPolicy(
|
||||
!lbProperties.isEnabled() || retryPolicy == null ? new NeverRetryPolicy()
|
||||
|
||||
@@ -2,7 +2,10 @@ package org.springframework.cloud.client.loadbalancer;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.retry.backoff.NoBackOffPolicy;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
@@ -21,5 +24,13 @@ public class RetryLoadBalancerAutoConfigurationTests extends AbstractLoadBalance
|
||||
ClientHttpRequestInterceptor interceptor = interceptors.get(0);
|
||||
assertThat(interceptor, is(instanceOf(RetryLoadBalancerInterceptor.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultBackOffPolicy() throws Exception {
|
||||
ConfigurableApplicationContext context = init(OneRestTemplate.class);
|
||||
LoadBalancedBackOffPolicyFactory loadBalancedBackOffPolicyFactory = context.getBean(LoadBalancedBackOffPolicyFactory.class);
|
||||
assertThat(loadBalancedBackOffPolicyFactory, is(instanceOf(LoadBalancedBackOffPolicyFactory.NoBackOffPolicyFactory.class)));
|
||||
assertThat(loadBalancedBackOffPolicyFactory.createBackOffPolicy("foo"), is(instanceOf(NoBackOffPolicy.class)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,11 @@ import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.mock.http.client.MockClientHttpResponse;
|
||||
import org.springframework.retry.RetryContext;
|
||||
import org.springframework.retry.backoff.BackOffContext;
|
||||
import org.springframework.retry.backoff.BackOffInterruptedException;
|
||||
import org.springframework.retry.backoff.BackOffPolicy;
|
||||
import org.springframework.retry.backoff.ExponentialBackOffPolicy;
|
||||
import org.springframework.retry.policy.NeverRetryPolicy;
|
||||
import org.springframework.retry.support.RetryTemplate;
|
||||
|
||||
@@ -37,6 +42,7 @@ public class RetryLoadBalancerInterceptorTest {
|
||||
private LoadBalancerClient client;
|
||||
private LoadBalancerRetryProperties lbProperties;
|
||||
private LoadBalancerRequestFactory lbRequestFactory;
|
||||
private LoadBalancedBackOffPolicyFactory backOffPolicyFactory = new LoadBalancedBackOffPolicyFactory.NoBackOffPolicyFactory();
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
@@ -62,7 +68,8 @@ public class RetryLoadBalancerInterceptorTest {
|
||||
when(client.choose(eq("foo"))).thenReturn(serviceInstance);
|
||||
when(client.execute(eq("foo"), eq(serviceInstance), any(LoadBalancerRequest.class))).thenThrow(new IOException());
|
||||
lbProperties.setEnabled(false);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbProperties, lbRetryPolicyFactory, lbRequestFactory);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbProperties, lbRetryPolicyFactory,
|
||||
lbRequestFactory, backOffPolicyFactory);
|
||||
byte[] body = new byte[]{};
|
||||
ClientHttpRequestExecution execution = mock(ClientHttpRequestExecution.class);
|
||||
|
||||
@@ -78,7 +85,8 @@ public class RetryLoadBalancerInterceptorTest {
|
||||
when(request.getURI()).thenReturn(new URI("http://foo_underscore"));
|
||||
LoadBalancedRetryPolicyFactory lbRetryPolicyFactory = mock(LoadBalancedRetryPolicyFactory.class);
|
||||
lbProperties.setEnabled(true);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbProperties, lbRetryPolicyFactory, lbRequestFactory);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbProperties, lbRetryPolicyFactory, lbRequestFactory,
|
||||
backOffPolicyFactory);
|
||||
byte[] body = new byte[]{};
|
||||
ClientHttpRequestExecution execution = mock(ClientHttpRequestExecution.class);
|
||||
ClientHttpResponse rsp = interceptor.intercept(request, body, execution);
|
||||
@@ -96,7 +104,8 @@ public class RetryLoadBalancerInterceptorTest {
|
||||
when(client.execute(eq("foo"), eq(serviceInstance), any(LoadBalancerRequest.class))).thenReturn(clientHttpResponse);
|
||||
when(this.lbRequestFactory.createRequest(any(), any(), any())).thenReturn(mock(LoadBalancerRequest.class));
|
||||
lbProperties.setEnabled(true);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbProperties, lbRetryPolicyFactory, lbRequestFactory);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbProperties, lbRetryPolicyFactory,
|
||||
lbRequestFactory, backOffPolicyFactory);
|
||||
byte[] body = new byte[]{};
|
||||
ClientHttpRequestExecution execution = mock(ClientHttpRequestExecution.class);
|
||||
interceptor.intercept(request, body, execution);
|
||||
@@ -117,7 +126,8 @@ public class RetryLoadBalancerInterceptorTest {
|
||||
when(client.execute(eq("foo"), eq(serviceInstance), any(LoadBalancerRequest.class))).thenReturn(clientHttpResponse);
|
||||
when(this.lbRequestFactory.createRequest(any(), any(), any())).thenReturn(mock(LoadBalancerRequest.class));
|
||||
lbProperties.setEnabled(true);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbProperties, lbRetryPolicyFactory, lbRequestFactory);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbProperties, lbRetryPolicyFactory,
|
||||
lbRequestFactory, backOffPolicyFactory);
|
||||
byte[] body = new byte[]{};
|
||||
ClientHttpRequestExecution execution = mock(ClientHttpRequestExecution.class);
|
||||
ClientHttpResponse rsp = interceptor.intercept(request, body, execution);
|
||||
@@ -143,7 +153,8 @@ public class RetryLoadBalancerInterceptorTest {
|
||||
when(client.execute(eq("foo"), eq(serviceInstance), nullable(LoadBalancerRequest.class))).
|
||||
thenReturn(clientHttpResponseNotFound).thenReturn(clientHttpResponseOk);
|
||||
lbProperties.setEnabled(true);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbProperties, lbRetryPolicyFactory, lbRequestFactory);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbProperties, lbRetryPolicyFactory,
|
||||
lbRequestFactory, backOffPolicyFactory);
|
||||
byte[] body = new byte[]{};
|
||||
ClientHttpRequestExecution execution = mock(ClientHttpRequestExecution.class);
|
||||
ClientHttpResponse rsp = interceptor.intercept(request, body, execution);
|
||||
@@ -162,18 +173,23 @@ public class RetryLoadBalancerInterceptorTest {
|
||||
when(policy.canRetryNextServer(any(LoadBalancedRetryContext.class))).thenReturn(true);
|
||||
LoadBalancedRetryPolicyFactory lbRetryPolicyFactory = mock(LoadBalancedRetryPolicyFactory.class);
|
||||
when(lbRetryPolicyFactory.create(eq("foo"), any(ServiceInstanceChooser.class))).thenReturn(policy);
|
||||
LoadBalancedBackOffPolicyFactory backOffPolicyFactory = mock(LoadBalancedBackOffPolicyFactory.class);
|
||||
MyBackOffPolicy backOffPolicy = new MyBackOffPolicy();
|
||||
when(backOffPolicyFactory.createBackOffPolicy(eq("foo"))).thenReturn(backOffPolicy);
|
||||
ServiceInstance serviceInstance = mock(ServiceInstance.class);
|
||||
when(client.choose(eq("foo"))).thenReturn(serviceInstance);
|
||||
when(client.execute(eq("foo"), eq(serviceInstance), any(LoadBalancerRequest.class))).thenThrow(new IOException()).thenReturn(clientHttpResponse);
|
||||
when(this.lbRequestFactory.createRequest(any(), any(), any())).thenReturn(mock(LoadBalancerRequest.class));
|
||||
lbProperties.setEnabled(true);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbProperties, lbRetryPolicyFactory, lbRequestFactory);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbProperties, lbRetryPolicyFactory, lbRequestFactory,
|
||||
backOffPolicyFactory);
|
||||
byte[] body = new byte[]{};
|
||||
ClientHttpRequestExecution execution = mock(ClientHttpRequestExecution.class);
|
||||
ClientHttpResponse rsp = interceptor.intercept(request, body, execution);
|
||||
verify(client, times(2)).execute(eq("foo"), eq(serviceInstance), any(LoadBalancerRequest.class));
|
||||
assertThat(rsp, is(clientHttpResponse));
|
||||
verify(lbRequestFactory, times(2)).createRequest(request, body, execution);
|
||||
assertThat(backOffPolicy.getBackoffAttempts(), is(1));
|
||||
}
|
||||
|
||||
@Test(expected = IOException.class)
|
||||
@@ -190,10 +206,35 @@ public class RetryLoadBalancerInterceptorTest {
|
||||
when(client.execute(eq("foo"), eq(serviceInstance), any(LoadBalancerRequest.class))).thenThrow(new IOException()).thenReturn(clientHttpResponse);
|
||||
when(this.lbRequestFactory.createRequest(any(), any(), any())).thenReturn(mock(LoadBalancerRequest.class));
|
||||
lbProperties.setEnabled(true);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbProperties, lbRetryPolicyFactory, lbRequestFactory);
|
||||
RetryLoadBalancerInterceptor interceptor = new RetryLoadBalancerInterceptor(client, lbProperties, lbRetryPolicyFactory,
|
||||
lbRequestFactory, backOffPolicyFactory);
|
||||
byte[] body = new byte[]{};
|
||||
ClientHttpRequestExecution execution = mock(ClientHttpRequestExecution.class);
|
||||
ClientHttpResponse rsp = interceptor.intercept(request, body, execution);
|
||||
verify(lbRequestFactory).createRequest(request, body, execution);
|
||||
}
|
||||
|
||||
class MyBackOffPolicy implements BackOffPolicy {
|
||||
|
||||
private int backoffAttempts = 0;
|
||||
|
||||
@Override
|
||||
public BackOffContext start(RetryContext retryContext) {
|
||||
return new BackOffContext() {
|
||||
@Override
|
||||
protected Object clone() throws CloneNotSupportedException {
|
||||
return super.clone();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public void backOff(BackOffContext backOffContext) throws BackOffInterruptedException {
|
||||
backoffAttempts++;
|
||||
}
|
||||
|
||||
public int getBackoffAttempts() {
|
||||
return backoffAttempts;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -12,7 +12,7 @@ public class PropertySourceBootstrapProperties {
|
||||
private boolean overrideSystemProperties = true;
|
||||
|
||||
/**
|
||||
* Flag to indicate that {@link #isSystemPropertiesOverride()
|
||||
* Flag to indicate that {@link #isOverrideSystemProperties()
|
||||
* systemPropertiesOverride} can be used. Set to false to prevent users from changing
|
||||
* the default accidentally. Default true.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user