javaspringspring-retry

How to access current retry interval value?


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
    }
}

Solution

  • 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