Skip to content

Commit 49fc854

Browse files
authored
Merge pull request eugenp#11703 from mdabrowski-eu/BAEL-5301
BAEL-5301 Retrying Feign Calls
2 parents 8155f46 + 2733f1e commit 49fc854

File tree

4 files changed

+127
-0
lines changed

4 files changed

+127
-0
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.baeldung.feign.retry;
2+
3+
4+
import feign.FeignException;
5+
import feign.Response;
6+
import feign.RetryableException;
7+
import feign.codec.ErrorDecoder;
8+
9+
import static feign.FeignException.errorStatus;
10+
11+
public class Custom5xxErrorDecoder implements ErrorDecoder {
12+
@Override
13+
public Exception decode(String methodKey, Response response) {
14+
FeignException exception = errorStatus(methodKey, response);
15+
int status = response.status();
16+
if (status >= 500) {
17+
return new RetryableException(
18+
response.status(),
19+
exception.getMessage(),
20+
response.request().httpMethod(),
21+
exception,
22+
null,
23+
response.request());
24+
}
25+
return exception;
26+
}
27+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.baeldung.feign.retry;
2+
3+
import feign.RetryableException;
4+
import feign.Retryer;
5+
6+
public class NaiveRetryer implements feign.Retryer {
7+
@Override
8+
public void continueOrPropagate(RetryableException e) {
9+
try {
10+
Thread.sleep(1000L);
11+
} catch (InterruptedException ex) {
12+
Thread.currentThread().interrupt();
13+
throw e;
14+
}
15+
}
16+
17+
@Override
18+
public Retryer clone() {
19+
return new NaiveRetryer();
20+
}
21+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.baeldung.feign.retry;
2+
3+
import com.baeldung.feign.clients.BookClient;
4+
import feign.Feign;
5+
import feign.Logger;
6+
import feign.Retryer;
7+
import feign.gson.GsonDecoder;
8+
import feign.gson.GsonEncoder;
9+
import feign.okhttp.OkHttpClient;
10+
import feign.slf4j.Slf4jLogger;
11+
import lombok.Getter;
12+
13+
import java.util.concurrent.TimeUnit;
14+
15+
@Getter
16+
public class ResilientFeignClientBuilder {
17+
public BookClient bookClient = createClient(BookClient.class, "http://localhost:8081/api/books");
18+
19+
public static <T> T createClient(Class<T> type, String uri) {
20+
return Feign.builder()
21+
.client(new OkHttpClient())
22+
.encoder(new GsonEncoder())
23+
.decoder(new GsonDecoder())
24+
.retryer(new Retryer.Default(100L, TimeUnit.SECONDS.toMillis(3L), 5))
25+
.errorDecoder(new Custom5xxErrorDecoder())
26+
.target(type, uri);
27+
}
28+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package com.baeldung.feign.retry;
2+
3+
import feign.*;
4+
import feign.codec.ErrorDecoder;
5+
import org.jetbrains.annotations.NotNull;
6+
import org.junit.Test;
7+
8+
import java.nio.charset.Charset;
9+
import java.util.Collection;
10+
import java.util.HashMap;
11+
12+
import static org.junit.Assert.assertFalse;
13+
import static org.junit.Assert.assertTrue;
14+
15+
public class Custom5xxErrorDecoderUnitTest {
16+
@Test
17+
public void given5xxResponse_whenDecode_thenReturnRetryableException() {
18+
// given
19+
ErrorDecoder decoder = new Custom5xxErrorDecoder();
20+
Response response = responseStub(500);
21+
22+
// when
23+
Exception exception = decoder.decode("GET", response);
24+
25+
// then
26+
assertTrue(exception instanceof RetryableException);
27+
}
28+
29+
@Test
30+
public void given4xxResponse_whenDecode_thenReturnFeignException() {
31+
// given
32+
ErrorDecoder decoder = new Custom5xxErrorDecoder();
33+
Response response = responseStub(400);
34+
35+
// when
36+
Exception exception = decoder.decode("GET", response);
37+
38+
// then
39+
assertTrue(exception instanceof FeignException);
40+
assertFalse(exception instanceof RetryableException);
41+
}
42+
43+
@NotNull
44+
private Response responseStub(int status) {
45+
return Response.builder()
46+
.request(Request.create(
47+
Request.HttpMethod.GET, "url", new HashMap<>(), new byte[0], Charset.defaultCharset(), new RequestTemplate()))
48+
.status(status)
49+
.build();
50+
}
51+
}

0 commit comments

Comments
 (0)