Spring @Retryable - how to log when it is invoked?

Justinas Jakavonis picture Justinas Jakavonis · Mar 2, 2018 · Viewed 18.2k times · Source

I use compile 'org.springframework.retry:spring-retry:1.2.2.RELEASE'with Spring Boot 1.5.9.RELEASE.

Configured to retry my method and it works well:

@Retryable(value = { IOException.class }, maxAttempts = 5, backoff = @Backoff(delay = 500))
public void someMethod(){...}

How to output some specific message when retry occurs?

Answer

whistling_marmot picture whistling_marmot · Jun 5, 2018

You can register a RetryListener:

@Bean
public List<RetryListener> retryListeners() {
    Logger log = LoggerFactory.getLogger(getClass());

    return Collections.singletonList(new RetryListener() {

        @Override
        public <T, E extends Throwable> boolean open(RetryContext context, RetryCallback<T, E> callback) {
            // The 'context.name' attribute has not been set on the context yet. So we have to use reflection.
            Field labelField = ReflectionUtils.findField(callback.getClass(), "val$label");
            ReflectionUtils.makeAccessible(labelField);
            String label = (String) ReflectionUtils.getField(labelField, callback);
            log.trace("Starting retryable method {}", label);
            return true;
        }

        @Override
        public <T, E extends Throwable> void onError(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
            log.warn("Retryable method {} threw {}th exception {}",
                    context.getAttribute("context.name"), context.getRetryCount(), throwable.toString());
        }

        @Override
        public <T, E extends Throwable> void close(RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
            log.trace("Finished retryable method {}", context.getAttribute("context.name"));
        }
    });

If you don't need to log from all 3 interception points, you can override RetryListenerSupport instead. For example:

@Bean
public List<RetryListener> retryListeners() {
    Logger log = LoggerFactory.getLogger(getClass());

    return Collections.singletonList(new RetryListenerSupport() {

        @Override
        public <T, E extends Throwable> void onError(
                RetryContext context, RetryCallback<T, E> callback, Throwable throwable) {
            log.warn("Retryable method {} threw {}th exception {}",
                    context.getAttribute("context.name"), 
                    context.getRetryCount(), throwable.toString());
        }
    });
}