Skip to content

Commit 23ca17d

Browse files
authored
Reuse serviceInstance for retries Fixes gh-840 (#841)
1 parent 647b0b3 commit 23ca17d

File tree

2 files changed

+47
-4
lines changed

2 files changed

+47
-4
lines changed

spring-cloud-openfeign-core/src/main/java/org/springframework/cloud/openfeign/loadbalancer/RetryableFeignBlockingLoadBalancerClient.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2013-2022 the original author or authors.
2+
* Copyright 2013-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -66,6 +66,7 @@
6666
*
6767
* @author Olga Maciaszek-Sharma
6868
* @author Wonsik Cheung
69+
* @author Andriy Pikozh
6970
* @since 2.2.6
7071
*/
7172
@SuppressWarnings({ "rawtypes", "unchecked" })
@@ -125,8 +126,8 @@ public Response execute(Request request, Request.Options options) throws IOExcep
125126
// and extract the server and update the request being made
126127
if (context instanceof LoadBalancedRetryContext) {
127128
LoadBalancedRetryContext lbContext = (LoadBalancedRetryContext) context;
128-
ServiceInstance serviceInstance = lbContext.getServiceInstance();
129-
if (serviceInstance == null) {
129+
retrievedServiceInstance = lbContext.getServiceInstance();
130+
if (retrievedServiceInstance == null) {
130131
if (LOG.isDebugEnabled()) {
131132
LOG.debug("Service instance retrieved from LoadBalancedRetryContext: was null. "
132133
+ "Reattempting service instance selection");

spring-cloud-openfeign-core/src/test/java/org/springframework/cloud/openfeign/loadbalancer/RetryableFeignBlockingLoadBalancerClientTests.java

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2013-2022 the original author or authors.
2+
* Copyright 2013-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -74,6 +74,7 @@
7474
* "https://github.com/spring-cloud/spring-cloud-commons/blob/main/spring-cloud-loadbalancer/src/test/java/org/springframework/cloud/loadbalancer/blocking/client/BlockingLoadBalancerClientTests.java">BlockingLoadBalancerClientTests</a>
7575
* @author Olga Maciaszek-Sharma
7676
* @author Wonsik Cheung
77+
* @author Andriy Pikozh
7778
*/
7879
@ExtendWith(MockitoExtension.class)
7980
class RetryableFeignBlockingLoadBalancerClientTests {
@@ -158,10 +159,51 @@ void shouldRetryOnRepeatableStatusCode() throws IOException {
158159

159160
feignBlockingLoadBalancerClient.execute(request, new Request.Options());
160161

162+
verify(loadBalancerClient, times(2)).choose(eq("test"), any());
161163
verify(loadBalancerClient, times(2)).reconstructURI(serviceInstance, URI.create("http://test/path"));
162164
verify(delegate, times(2)).execute(any(), any());
163165
}
164166

167+
@Test
168+
void shouldReuseServerInstanceOnSameInstanceRetry() throws IOException {
169+
properties.getRetry().setMaxRetriesOnSameServiceInstance(1);
170+
properties.getRetry().setMaxRetriesOnNextServiceInstance(0);
171+
properties.getRetry().getRetryableStatusCodes().add(503);
172+
Request request = testRequest();
173+
Response response = testResponse(503);
174+
when(delegate.execute(any(), any())).thenReturn(response);
175+
when(retryFactory.createRetryPolicy(any(), eq(loadBalancerClient)))
176+
.thenReturn(new BlockingLoadBalancedRetryPolicy(properties));
177+
when(loadBalancerClient.reconstructURI(serviceInstance, URI.create("http://test/path")))
178+
.thenReturn(URI.create("http://testhost:80/path"));
179+
180+
feignBlockingLoadBalancerClient.execute(request, new Request.Options());
181+
182+
verify(loadBalancerClient, times(1)).choose(eq("test"), any());
183+
verify(loadBalancerClient, times(2)).reconstructURI(serviceInstance, URI.create("http://test/path"));
184+
verify(delegate, times(2)).execute(any(), any());
185+
}
186+
187+
@Test
188+
void shouldReuseServerInstanceOnSameInstanceRetryWithBothSameAndNextRetries() throws IOException {
189+
properties.getRetry().setMaxRetriesOnSameServiceInstance(1);
190+
properties.getRetry().setMaxRetriesOnNextServiceInstance(1);
191+
properties.getRetry().getRetryableStatusCodes().add(503);
192+
Request request = testRequest();
193+
Response response = testResponse(503);
194+
when(delegate.execute(any(), any())).thenReturn(response);
195+
when(retryFactory.createRetryPolicy(any(), eq(loadBalancerClient)))
196+
.thenReturn(new BlockingLoadBalancedRetryPolicy(properties));
197+
when(loadBalancerClient.reconstructURI(serviceInstance, URI.create("http://test/path")))
198+
.thenReturn(URI.create("http://testhost:80/path"));
199+
200+
feignBlockingLoadBalancerClient.execute(request, new Request.Options());
201+
202+
verify(loadBalancerClient, times(2)).choose(eq("test"), any());
203+
verify(loadBalancerClient, times(4)).reconstructURI(serviceInstance, URI.create("http://test/path"));
204+
verify(delegate, times(4)).execute(any(), any());
205+
}
206+
165207
@Test
166208
void shouldNotRetryOnDisabled() throws IOException {
167209
properties.getRetry().setEnabled(false);

0 commit comments

Comments
 (0)