Iam hosting a sample service at 8081 port. The request goes through spring cloud gateway. the configuration is as follows:
spring:
cloud:
gateway:
routes:
- id: retry_test
uri: http://localhost:8081
predicates:
- Path=/location
filters:
- name: Retry
args:
retries: 3
statuses: INTERNAL_SERVER_ERROR
methods: GET
exceptions: java.net.ConnectException
I stopped the application and hit the gateway but the gateway did not retry the request which was expected from the yaml configuration.
Can somebody point the issue with the approach?
This seems to be bug with RetryFilterFunctions. If you see their code
SimpleRetryPolicy simpleRetryPolicy = new SimpleRetryPolicy(config.getRetries(), retryableExceptions);
compositeRetryPolicy.setPolicies((RetryPolicy[])Arrays.asList(simpleRetryPolicy, new HttpRetryPolicy(config)).toArray(new RetryPolicy[0]));
RetryTemplate retryTemplate = retryTemplateBuilder.customPolicy(compositeRetryPolicy).build();
They build compositeRetry policy with HttpRetryPolicy as second policy which is internal class and extends NeverRetryPolicy and on CompositePolicy they do not set optimistic = true hence even though first policy’s canRetry returns true, overall canRetry for composite policy is returned as false hence retry for exceptions does not work. You can create your own custom retry filter using Spring RetryTemplate
@AllArgsConstructor
private class RetryWIthDelay implements HandlerFilterFunction<ServerResponse, ServerResponse>
{
private int count = 0;
private long delayBeforeRetry = 10L;
private Set<Class> exceptionList;
private Set<HttpStatusCode> retryStatusCodes;
@Override
public ServerResponse filter(ServerRequest request, HandlerFunction<ServerResponse> next) throws Exception
{
RetryTemplateBuilder templateBuilder = RetryTemplate.builder();
Map<Class<? extends Throwable>, Boolean> exceptionsToRetry = new HashMap();
exceptionList.stream().forEach(eachExceptionClass -> exceptionsToRetry.put(eachExceptionClass, true));
SimpleRetryPolicy simpleRetryPolicy = new SimpleRetryPolicy(count, exceptionsToRetry);
RetryTemplate retryTemplate = templateBuilder.customPolicy(simpleRetryPolicy)
.fixedBackoff(Duration.ofSeconds(delayBeforeRetry))
.build();
return retryTemplate.execute((context) -> {
ServerResponse downStreamReponse = next.handle(request);
return downStreamReponse;
});
}
}
This above filter can be configured as below, I did not try configuring same in application.yml but have create Bean with this
return GatewayRouterFunctions.route("retry_test1")
.filter(new RetryWIthDelay(
5,
10,
Set.of(ConnectException.class),
Set.of(HttpStatus.BAD_GATEWAY)))
.build();
Manadeep is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.