web-dev-qa-db-fra.com

Spring @Retryable - comment se connecter quand il est invoqué?

J'utilise compile 'org.springframework.retry:spring-retry:1.2.2.RELEASE'avec Spring Boot 1.5.9.RELEASE.

Configuré pour réessayer ma méthode et cela fonctionne bien:

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

Comment afficher un message spécifique lors d'une nouvelle tentative?

9
Justas

En parcourant le code, le org.springframework.retry.support.RetryTemplate exécute la logique de nouvelle tentative pour réessayer les opérations. Ce modèle enregistre uniquement des éléments simples tels que:

o.s.retry.support.RetryTemplate          : Retry: count=0
o.s.retry.support.RetryTemplate          : Checking for rethrow: count=1
o.s.retry.support.RetryTemplate          : Retry: count=1
o.s.retry.support.RetryTemplate          : Checking for rethrow: count=2
o.s.retry.support.RetryTemplate          : Retry: count=2
o.s.retry.support.RetryTemplate          : Checking for rethrow: count=3
o.s.retry.support.RetryTemplate          : Retry failed last attempt: count=3

Si vous souhaitez enregistrer l'exception spécifique, vous pouvez intercepter le journal d'exception et recommencer. Malheureusement, pour autant que je puisse voir, il n'y a aucun moyen d'enregistrer des messages personnalisés dans le cadre.

Une autre méthode serait d'occulter l'intercepteur réel responsable de l'invocation de votre méthode comme RetryOperationsInterceptor, ce n'est cependant pas conseillé.

4
Konstantin

Vous pouvez enregistrer un 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"));
        }
    });

Si vous n'avez pas besoin de vous connecter à partir des 3 points d'interception, vous pouvez remplacer RetryListenerSupport à la place. Par exemple:

@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());
        }
    });
}
14
whistling_marmot