I have a situation in which I wanted to implement an API retry mechanism. Let say I have an API that calls third party API where normal response time comes under 2 seconds but sometimes we got an error saying "Service Not available", "Gateway Timeout" Etc.
So I went online to see if we have a library to handle these things and I found out https://jodah.net/failsafe/
Purpose Of using Library:-
If under 5 seconds, I don't get the result, I will cancel the execution of the current call and try one more time.
For that, In Library I can see we have timeout and retry policy.
First I am trying the timeout.
Timeout<Object> timeout = Timeout.of(Duration.ofMillis(1000)).withCancel(true)
.onFailure(e -> logger.error("Connection attempt timed out {} {} ",new DateTime(), e.getFailure()))
.onSuccess(e -> logger.info("Execution completed on time"));
try {
logger.info("TIme: {}", new DateTime());
result = Failsafe.with(timeout).get(() -> restTemplate.postForEntity(messageSendServiceUrl, request, String.class));
} catch (TimeoutExceededException | HttpClientErrorException e) {
logger.info("TIme: {}", new DateTime());
logger.error("Timeout exception", e);
} catch (Exception e) {
logger.error("Exception", e);
}
But while calculating the time I am getting 20 seconds delay between calling the API and receiving TimeoutExceededException
, which should be 1 second as duration is Duration.ofMillis(1000)
. Below you can see a difference of 21 seconds.
TIme: 2020-06-11T10:00:17.964+05:30
Connection attempt timed out 2020-06-11T10:00:39.037+05:30 {}
Can you please let me know what I am doing wrong here.
Second is the retry policy
RetryPolicy<Object> retryPolicy = new RetryPolicy<>()
.handle(HttpClientErrorException.class, TimeoutExceededException.class, Exception.class)
.withDelay(Duration.ofSeconds(1))
.withMaxRetries(3);
I want once TimeoutExceededException
exception occurs after let's say 3 seconds, with a delay of 1 second, again the request is fired with max 3 retries.
I am using it as
result = Failsafe.with(retryPolicy,timeout).get(() -> restTemplate.postForEntity(messageSendServiceUrl, request, String.class));