Skip to content

Commit 1badef9

Browse files
committed
Merge remote-tracking branch 'origin/2.2.x'
# Conflicts: # docs/src/main/asciidoc/spring-cloud-commons.adoc # spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/InterceptorRetryPolicy.java # spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerAutoConfiguration.java # spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/RetryLoadBalancerInterceptor.java # spring-cloud-commons/src/test/java/org/springframework/cloud/client/loadbalancer/AbstractLoadBalancerAutoConfigurationTests.java # spring-cloud-commons/src/test/java/org/springframework/cloud/client/loadbalancer/InterceptorRetryPolicyTest.java # spring-cloud-loadbalancer/src/main/java/org/springframework/cloud/loadbalancer/config/BlockingLoadBalancerClientAutoConfiguration.java # spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/config/BlockingLoadBalancerClientAutoConfigurationTests.java
2 parents 0066899 + 5401628 commit 1badef9

File tree

12 files changed

+421
-61
lines changed

12 files changed

+421
-61
lines changed

docs/src/main/asciidoc/_configprops.adoc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@
3636
|spring.cloud.loadbalancer.health-check.path | |
3737
|spring.cloud.loadbalancer.hint | | Allows setting the value of <code>hint</code> that is passed on to the LoadBalancer request and can subsequently be used in {@link ReactiveLoadBalancer} implementations.
3838
|spring.cloud.loadbalancer.retry.enabled | true |
39+
|spring.cloud.loadbalancer.retry.max-retries-on-next-service-instance | 1 | Number of retries to be executed on the next <code>ServiceInstance</code>. A <code>ServiceInstance</code> is chosen before each retry call.
40+
|spring.cloud.loadbalancer.retry.max-retries-on-same-service-instance | 0 | Number of retries to be executed on the same <code>ServiceInstance</code>.
41+
|spring.cloud.loadbalancer.retry.retry-on-all-operations | false | Indicates retries should be attempted on operations other than {@link HttpMethod#GET}.
42+
|spring.cloud.loadbalancer.retry.retryable-status-codes | | A {@link Set} of status codes that should trigger a retry.
3943
|spring.cloud.loadbalancer.ribbon.enabled | true | Causes `RibbonLoadBalancerClient` to be used by default.
4044
|spring.cloud.loadbalancer.service-discovery.timeout | | String representation of Duration of the timeout for calls to service discovery.
4145
|spring.cloud.loadbalancer.zone | | Spring Cloud LoadBalancer zone.

docs/src/main/asciidoc/spring-cloud-commons.adoc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -438,10 +438,16 @@ Then, `ReactiveLoadBalancer` is used underneath.
438438
A load-balanced `RestTemplate` can be configured to retry failed requests.
439439
By default, this logic is disabled.
440440
You can enable it by adding link:https://github.com/spring-projects/spring-retry[Spring Retry] to your application's classpath.
441+
441442
If you would like to disable the retry logic with Spring Retry on the classpath, you can set `spring.cloud.loadbalancer.retry.enabled=false`.
442443

443-
If you would like to implement a `BackOffPolicy` in your retries, you need to create a bean of type `LoadBalancedRetryFactory` and override the `createBackOffPolicy` method:
444+
If you would like to implement a `BackOffPolicy` in your retries, you need to create a bean of type `LoadBalancedRetryFactory` and override the `createBackOffPolicy()` method.
445+
446+
You can set:
444447

448+
- `spring.cloud.loadbalancer.retry.maxRetriesOnSameServiceInstance` - indicates how many times a request should be retried on the same `ServiceInstance` (counted separately for every selected instance)
449+
- `spring.cloud.loadbalancer.retry.maxRetriesOnNextServiceInstance` - indicates how many times a request should be retried a newly selected `ServiceInstance`
450+
- `spring.cloud.loadbalancer.retry.retryableStatusCodes` - the status codes on which to always retry a failed request.
445451
====
446452
[source,java,indent=0]
447453
----

spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/InterceptorRetryPolicy.java

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,13 @@
2828
*/
2929
public class InterceptorRetryPolicy implements RetryPolicy {
3030

31-
private HttpRequest request;
31+
private final HttpRequest request;
3232

33-
private LoadBalancedRetryPolicy policy;
33+
private final LoadBalancedRetryPolicy policy;
3434

35-
private ServiceInstanceChooser serviceInstanceChooser;
35+
private final ServiceInstanceChooser serviceInstanceChooser;
3636

37-
private String serviceName;
37+
private final String serviceName;
3838

3939
/**
4040
* Creates a new retry policy.
@@ -56,20 +56,20 @@ public boolean canRetry(RetryContext context) {
5656
LoadBalancedRetryContext lbContext = (LoadBalancedRetryContext) context;
5757
if (lbContext.getRetryCount() == 0 && lbContext.getServiceInstance() == null) {
5858
// We haven't even tried to make the request yet so return true so we do
59-
lbContext.setServiceInstance(this.serviceInstanceChooser.choose(this.serviceName));
59+
lbContext.setServiceInstance(serviceInstanceChooser.choose(serviceName));
6060
return true;
6161
}
62-
return this.policy.canRetryNextServer(lbContext);
62+
return policy.canRetryNextServer(lbContext);
6363
}
6464

6565
@Override
6666
public RetryContext open(RetryContext parent) {
67-
return new LoadBalancedRetryContext(parent, this.request);
67+
return new LoadBalancedRetryContext(parent, request);
6868
}
6969

7070
@Override
7171
public void close(RetryContext context) {
72-
this.policy.close((LoadBalancedRetryContext) context);
72+
policy.close((LoadBalancedRetryContext) context);
7373
}
7474

7575
@Override
@@ -79,7 +79,7 @@ public void registerThrowable(RetryContext context, Throwable throwable) {
7979
// increases the retry count
8080
lbContext.registerThrowable(throwable);
8181
// let the policy know about the exception as well
82-
this.policy.registerThrowable(lbContext, throwable);
82+
policy.registerThrowable(lbContext, throwable);
8383
}
8484

8585
@Override
@@ -93,25 +93,25 @@ public boolean equals(Object o) {
9393

9494
InterceptorRetryPolicy that = (InterceptorRetryPolicy) o;
9595

96-
if (!this.request.equals(that.request)) {
96+
if (!request.equals(that.request)) {
9797
return false;
9898
}
99-
if (!this.policy.equals(that.policy)) {
99+
if (!policy.equals(that.policy)) {
100100
return false;
101101
}
102-
if (!this.serviceInstanceChooser.equals(that.serviceInstanceChooser)) {
102+
if (!serviceInstanceChooser.equals(that.serviceInstanceChooser)) {
103103
return false;
104104
}
105-
return this.serviceName.equals(that.serviceName);
105+
return serviceName.equals(that.serviceName);
106106

107107
}
108108

109109
@Override
110110
public int hashCode() {
111-
int result = this.request.hashCode();
112-
result = 31 * result + this.policy.hashCode();
113-
result = 31 * result + this.serviceInstanceChooser.hashCode();
114-
result = 31 * result + this.serviceName.hashCode();
111+
int result = request.hashCode();
112+
result = 31 * result + policy.hashCode();
113+
result = 31 * result + serviceInstanceChooser.hashCode();
114+
result = 31 * result + serviceName.hashCode();
115115
return result;
116116
}
117117

spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerAutoConfiguration.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
import org.springframework.web.client.RestTemplate;
3939

4040
/**
41-
* Auto-configuration for blocking (client-side load balancing).
41+
* Auto-configuration for blocking client-side load balancing.
4242
*
4343
* @author Spencer Gibb
4444
* @author Dave Syer

spring-cloud-commons/src/main/java/org/springframework/cloud/client/loadbalancer/LoadBalancerRetryProperties.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,11 @@
1616

1717
package org.springframework.cloud.client.loadbalancer;
1818

19+
import java.util.HashSet;
20+
import java.util.Set;
21+
1922
import org.springframework.boot.context.properties.ConfigurationProperties;
23+
import org.springframework.http.HttpMethod;
2024

2125
/**
2226
* Configuration properties for the {@link LoadBalancerClient}.
@@ -28,6 +32,28 @@ public class LoadBalancerRetryProperties {
2832

2933
private boolean enabled = true;
3034

35+
/**
36+
* Indicates retries should be attempted on operations other than
37+
* {@link HttpMethod#GET}.
38+
*/
39+
private boolean retryOnAllOperations = false;
40+
41+
/**
42+
* Number of retries to be executed on the same <code>ServiceInstance</code>.
43+
*/
44+
private int maxRetriesOnSameServiceInstance = 0;
45+
46+
/**
47+
* Number of retries to be executed on the next <code>ServiceInstance</code>. A
48+
* <code>ServiceInstance</code> is chosen before each retry call.
49+
*/
50+
private int maxRetriesOnNextServiceInstance = 1;
51+
52+
/**
53+
* A {@link Set} of status codes that should trigger a retry.
54+
*/
55+
private Set<Integer> retryableStatusCodes = new HashSet<>();
56+
3157
/**
3258
* Returns true if the load balancer should retry failed requests.
3359
* @return True if the load balancer should retry failed requests; false otherwise.
@@ -44,4 +70,36 @@ public void setEnabled(boolean enabled) {
4470
this.enabled = enabled;
4571
}
4672

73+
public boolean isRetryOnAllOperations() {
74+
return retryOnAllOperations;
75+
}
76+
77+
public void setRetryOnAllOperations(boolean retryOnAllOperations) {
78+
this.retryOnAllOperations = retryOnAllOperations;
79+
}
80+
81+
public int getMaxRetriesOnSameServiceInstance() {
82+
return maxRetriesOnSameServiceInstance;
83+
}
84+
85+
public void setMaxRetriesOnSameServiceInstance(int maxRetriesOnSameServiceInstance) {
86+
this.maxRetriesOnSameServiceInstance = maxRetriesOnSameServiceInstance;
87+
}
88+
89+
public int getMaxRetriesOnNextServiceInstance() {
90+
return maxRetriesOnNextServiceInstance;
91+
}
92+
93+
public void setMaxRetriesOnNextServiceInstance(int maxRetriesOnNextServiceInstance) {
94+
this.maxRetriesOnNextServiceInstance = maxRetriesOnNextServiceInstance;
95+
}
96+
97+
public Set<Integer> getRetryableStatusCodes() {
98+
return retryableStatusCodes;
99+
}
100+
101+
public void setRetryableStatusCodes(Set<Integer> retryableStatusCodes) {
102+
this.retryableStatusCodes = retryableStatusCodes;
103+
}
104+
47105
}

spring-cloud-commons/src/test/java/org/springframework/cloud/client/loadbalancer/InterceptorRetryPolicyTest.java

Lines changed: 37 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,14 @@
2020
import org.junit.Before;
2121
import org.junit.Test;
2222
import org.junit.runner.RunWith;
23-
import org.mockito.runners.MockitoJUnitRunner;
23+
import org.mockito.junit.MockitoJUnitRunner;
2424

2525
import org.springframework.cloud.client.ServiceInstance;
2626
import org.springframework.http.HttpRequest;
2727
import org.springframework.retry.RetryContext;
2828

2929
import static org.assertj.core.api.BDDAssertions.then;
30-
import static org.mockito.Matchers.eq;
30+
import static org.mockito.ArgumentMatchers.eq;
3131
import static org.mockito.Mockito.mock;
3232
import static org.mockito.Mockito.times;
3333
import static org.mockito.Mockito.verify;
@@ -49,90 +49,89 @@ public class InterceptorRetryPolicyTest {
4949

5050
@Before
5151
public void setup() {
52-
this.request = mock(HttpRequest.class);
53-
this.policy = mock(LoadBalancedRetryPolicy.class);
54-
this.serviceInstanceChooser = mock(ServiceInstanceChooser.class);
55-
this.serviceName = "foo";
52+
request = mock(HttpRequest.class);
53+
policy = mock(LoadBalancedRetryPolicy.class);
54+
serviceInstanceChooser = mock(ServiceInstanceChooser.class);
55+
serviceName = "foo";
5656
}
5757

5858
@After
5959
public void teardown() {
60-
this.request = null;
61-
this.policy = null;
62-
this.serviceInstanceChooser = null;
63-
this.serviceName = null;
60+
request = null;
61+
policy = null;
62+
serviceInstanceChooser = null;
63+
serviceName = null;
6464
}
6565

6666
@Test
67-
public void canRetryBeforeExecution() throws Exception {
68-
InterceptorRetryPolicy interceptorRetryPolicy = new InterceptorRetryPolicy(this.request, this.policy,
69-
this.serviceInstanceChooser, this.serviceName);
67+
public void canRetryBeforeExecution() {
68+
InterceptorRetryPolicy interceptorRetryPolicy = new InterceptorRetryPolicy(request, policy,
69+
serviceInstanceChooser, serviceName);
7070
LoadBalancedRetryContext context = mock(LoadBalancedRetryContext.class);
7171
when(context.getRetryCount()).thenReturn(0);
7272
ServiceInstance serviceInstance = mock(ServiceInstance.class);
73-
when(this.serviceInstanceChooser.choose(eq(this.serviceName))).thenReturn(serviceInstance);
73+
when(serviceInstanceChooser.choose(eq(serviceName))).thenReturn(serviceInstance);
7474
then(interceptorRetryPolicy.canRetry(context)).isTrue();
7575
verify(context, times(1)).setServiceInstance(eq(serviceInstance));
7676

7777
}
7878

7979
@Test
80-
public void canRetryNextServer() throws Exception {
81-
InterceptorRetryPolicy interceptorRetryPolicy = new InterceptorRetryPolicy(this.request, this.policy,
82-
this.serviceInstanceChooser, this.serviceName);
80+
public void canRetryNextServer() {
81+
InterceptorRetryPolicy interceptorRetryPolicy = new InterceptorRetryPolicy(request, policy,
82+
serviceInstanceChooser, serviceName);
8383
LoadBalancedRetryContext context = mock(LoadBalancedRetryContext.class);
8484
when(context.getRetryCount()).thenReturn(1);
85-
when(this.policy.canRetryNextServer(eq(context))).thenReturn(true);
85+
when(policy.canRetryNextServer(eq(context))).thenReturn(true);
8686
then(interceptorRetryPolicy.canRetry(context)).isTrue();
8787
}
8888

8989
@Test
90-
public void cannotRetry() throws Exception {
91-
InterceptorRetryPolicy interceptorRetryPolicy = new InterceptorRetryPolicy(this.request, this.policy,
92-
this.serviceInstanceChooser, this.serviceName);
90+
public void cannotRetry() {
91+
InterceptorRetryPolicy interceptorRetryPolicy = new InterceptorRetryPolicy(request, policy,
92+
serviceInstanceChooser, serviceName);
9393
LoadBalancedRetryContext context = mock(LoadBalancedRetryContext.class);
9494
when(context.getRetryCount()).thenReturn(1);
9595
then(interceptorRetryPolicy.canRetry(context)).isFalse();
9696
}
9797

9898
@Test
99-
public void open() throws Exception {
100-
InterceptorRetryPolicy interceptorRetryPolicy = new InterceptorRetryPolicy(this.request, this.policy,
101-
this.serviceInstanceChooser, this.serviceName);
99+
public void open() {
100+
InterceptorRetryPolicy interceptorRetryPolicy = new InterceptorRetryPolicy(request, policy,
101+
serviceInstanceChooser, serviceName);
102102
RetryContext context = interceptorRetryPolicy.open(null);
103103
then(context).isInstanceOf(LoadBalancedRetryContext.class);
104104
}
105105

106106
@Test
107-
public void close() throws Exception {
108-
InterceptorRetryPolicy interceptorRetryPolicy = new InterceptorRetryPolicy(this.request, this.policy,
109-
this.serviceInstanceChooser, this.serviceName);
107+
public void close() {
108+
InterceptorRetryPolicy interceptorRetryPolicy = new InterceptorRetryPolicy(request, policy,
109+
serviceInstanceChooser, serviceName);
110110
LoadBalancedRetryContext context = mock(LoadBalancedRetryContext.class);
111111
interceptorRetryPolicy.close(context);
112-
verify(this.policy, times(1)).close(eq(context));
112+
verify(policy, times(1)).close(eq(context));
113113
}
114114

115115
@Test
116-
public void registerThrowable() throws Exception {
117-
InterceptorRetryPolicy interceptorRetryPolicy = new InterceptorRetryPolicy(this.request, this.policy,
118-
this.serviceInstanceChooser, this.serviceName);
116+
public void registerThrowable() {
117+
InterceptorRetryPolicy interceptorRetryPolicy = new InterceptorRetryPolicy(request, policy,
118+
serviceInstanceChooser, serviceName);
119119
LoadBalancedRetryContext context = mock(LoadBalancedRetryContext.class);
120120
Throwable thrown = new Exception();
121121
interceptorRetryPolicy.registerThrowable(context, thrown);
122122
verify(context, times(1)).registerThrowable(eq(thrown));
123-
verify(this.policy, times(1)).registerThrowable(eq(context), eq(thrown));
123+
verify(policy, times(1)).registerThrowable(eq(context), eq(thrown));
124124
}
125125

126126
@Test
127-
public void equals() throws Exception {
128-
InterceptorRetryPolicy interceptorRetryPolicy = new InterceptorRetryPolicy(this.request, this.policy,
129-
this.serviceInstanceChooser, this.serviceName);
127+
public void equals() {
128+
InterceptorRetryPolicy interceptorRetryPolicy = new InterceptorRetryPolicy(request, policy,
129+
serviceInstanceChooser, serviceName);
130130
then(interceptorRetryPolicy.equals(null)).isFalse();
131131
then(interceptorRetryPolicy.equals(new Object())).isFalse();
132132
then(interceptorRetryPolicy.equals(interceptorRetryPolicy)).isTrue();
133-
then(interceptorRetryPolicy.equals(
134-
new InterceptorRetryPolicy(this.request, this.policy, this.serviceInstanceChooser, this.serviceName)))
135-
.isTrue();
133+
then(interceptorRetryPolicy
134+
.equals(new InterceptorRetryPolicy(request, policy, serviceInstanceChooser, serviceName))).isTrue();
136135
}
137136

138137
}

spring-cloud-loadbalancer/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,11 @@
7777
<version>${evictor.version}</version>
7878
<optional>true</optional>
7979
</dependency>
80+
<dependency>
81+
<groupId>org.springframework.retry</groupId>
82+
<artifactId>spring-retry</artifactId>
83+
<optional>true</optional>
84+
</dependency>
8085
<dependency>
8186
<groupId>org.springframework.boot</groupId>
8287
<artifactId>spring-boot-starter-test</artifactId>

0 commit comments

Comments
 (0)