I am using Spring Retry by creating a RetryTemplate
as follows:
import com.example.MyRetryProperties;
import com.example.SomeRetryableException;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.retry.support.RetryTemplate;
@Configuration
@EnableRetry
@RequiredArgsConstructor
public class RetryConfiguration {
private final MyRetryProperties retryProperties;
@Bean
public RetryTemplate retryTemplate() {
return RetryTemplate.builder()
.exponentialBackoff(
retryProperties.getInitialInterval(), // 500ms
retryProperties.getMultiplier(), // 2.0
retryProperties.getMaxInterval(), // 2000ms
false)
.withTimeout(retryProperties.getTimeout())
.retryOn(MyRetryableException.class)
.traversingCauses()
.build();
}
}
If a retry is in progress, I know that I can access the current retry count using RetryContext#getRetryCount
. Is it possible somehow to access the current interval value without calculating it based on the retry count (e.g. also from the context)?
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.RetryListener;
public class MyRetryListener implements RetryListener {
@Override
public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
int retryCount = context.getRetryCount();
System.out.println("Current retryCount: " + retryCount); // e.g. 3
int currentRetryInterval = // how?
System.out.println("Current retry interval: " + currentRetryInterval); // e.g. 2000ms for the third retry
}
}
The RetryContext
doesn't know anything about the strategy that is being used so the only common denominator you can access is the retryCount
. The only way is to do the calculation yourself, which means your listener needs to know which BackOffPolicy
is being used.
You could use the getAttribute
from the RetryContext
to get the BackOffContext
, but trying to cast it to the actual one will probably fail.
You might need to use reflection to actually get access to the field containing the calculated interval.
import org.springframework.retry.RetryCallback;
import org.springframework.retry.RetryContext;
import org.springframework.retry.RetryListener;
import org.springframework.util.ReflectionUtils;
public class MyRetrListener implements RetryListener {
@Override
public <T, E extends Throwable> void onError(RetryContext context,
RetryCallback<T, E> callback,
Throwable throwable) {
Object backOffPolicy = context.getAttribute("backOffContext");
var intervalField = ReflectionUtils.findField(backOffPolicy.getClass(), "interval");
var maxIntervalField = ReflectionUtils.findField(backOffPolicy.getClass(), "maxInterval");
intervalField.setAccessible(true);
maxIntervalField.setAccessible(true);
long interval = (long) ReflectionUtils.getField(intervalField, backOffPolicy);
long maxInterval = (long) ReflectionUtils.getField(maxIntervalField, backOffPolicy);
long currentRetryInterval = Math.min(interval, maxInterval);
System.out.println("Retry count: " + context.getRetryCount());
System.out.println("Current retry interval: " + currentRetryInterval);
}
}
Result for 4 retries as expected:
Retry count: 1
Current retry interval: 500
Retry count: 2
Current retry interval: 1000
Retry count: 3
Current retry interval: 2000
Retry count: 4
Current retry interval: 2000