Como você implementa um re-try-catch?

203

Try-catch destina-se a ajudar no tratamento de exceções. Isso significa que, de alguma forma, isso ajudará nosso sistema a ser mais robusto: tente se recuperar de um evento inesperado.

Suspeitamos que algo possa acontecer durante a execução e a instrução (envio de uma mensagem), para que seja incluído na tentativa. Se algo quase inesperado acontecer, podemos fazer algo: escrevemos o problema. Acho que não ligamos para registrar a exceção. Eu acho que o bloco catch é para nos dar a oportunidade de se recuperar do erro.

Agora, digamos que nos recuperamos do erro, porque conseguimos consertar o que estava errado. Pode ser super legal fazer uma nova tentativa:

try{ some_instruction(); }
catch (NearlyUnexpectedException e){
   fix_the_problem();
   retry;
}

Isso cairia rapidamente no loop eterno, mas digamos que o fix_the_problem retorne true e tente novamente. Dado que não existe tal coisa em Java, como você resolveria esse problema? Qual seria o seu melhor código de design para resolver isso?

Isso é como uma pergunta filosófica, já que eu já sei o que estou pedindo não é diretamente suportado pelo Java.

Andres Farias
fonte
5
Que tipo de exceção é essa?
Bhesh Gurung
23
Eu gosto do nome da sua exceção. ;)
Rohit Jain
De fato, não há muitas exceções das quais você pode se recuperar. Admito que minha motivação inicial não foi uma exceção real, mas uma maneira de evitar um se isso acontecer quase nunca: tento remove()partir de um java.util.Queue, que torce e InvalidElementExceptionquando a fila está vazia. Em vez de perguntar se está vazio, eu organizo as ações em um try-catch (que sob concorrência se torna obrigatório mesmo com o if anterior). Nesse caso, no catchbloco, eu pediria para encher a fila com mais elementos e, em seguida, tente novamente. Voila.
Andres Farias
1
Eu posso ver que a maneira usual de fazer isso seria no acesso ao banco de dados, se a conexão falhar na reconexão, se ela falhar, em seguida, lance uma exceção maior, caso contrário, tente novamente a chamada. Como já foi dito, poderíamos fazê-lo em um loop com uma verificação na parte inferior se (erro <> 0), em seguida, voltar caso contrário;
Theresa Forster

Respostas:

304

Você precisa colocar seu try-catchinterior em um whileloop como este: -

int count = 0;
int maxTries = 3;
while(true) {
    try {
        // Some Code
        // break out of loop, or return, on success
    } catch (SomeException e) {
        // handle exception
        if (++count == maxTries) throw e;
    }
}

Eu tomei counte maxTriespara evitar correr em um loop infinito, caso a exceção continue ocorrendo no seu try block.

Rohit Jain
fonte
3
Pensei em algo assim no começo, sem os maxTries. Obrigado pela resposta!
Andres Farias
6
@AndresFarias .. Sim, o ponto mais importante nesta resposta é incluir a maxTries. infinite loopCaso contrário, ele será executado se o usuário fornecer continuamente informações incorretas e, portanto, não sairá. De nada, porém. :)
Rohit Jain
obrigado por isso - isso me salvou de ter que escrever um código muito complicado!
9788 David Guimarães
2
É possível adicionar a função Thread.sleep () dentro da captura aqui. Porque, em alguns casos, como esperar pela resposta da página na biblioteca do Selenium que se tornou crítica. Obrigado.
Suat Atan PhD
2
Funciona bem! Para iniciantes: Se você receber um loop infinito positivo, verifique se Você adicionou "break"; no final do bloco "try".
Krzysztof Walczewski
59

Solução obrigatória de "empresa":

public abstract class Operation {
    abstract public void doIt();
    public void handleException(Exception cause) {
        //default impl: do nothing, log the exception, etc.
    }
}

public class OperationHelper {
    public static void doWithRetry(int maxAttempts, Operation operation) {
        for (int count = 0; count < maxAttempts; count++) {
            try {
                operation.doIt();
                count = maxAttempts; //don't retry
            } catch (Exception e) {
                operation.handleException(e);
            }
        }
    }
}

E para ligar para:

OperationHelper.doWithRetry(5, new Operation() {
    @Override public void doIt() {
        //do some stuff
    }
    @Override public void handleException(Exception cause) {
        //recover from the Exception
    }
});
ach
fonte
6
Você deve repetir a exceção se a última tentativa falhar, conforme feito nas outras respostas fornecidas.
285:
35

Como sempre, o melhor design depende das circunstâncias particulares. Normalmente, porém, escrevo algo como:

for (int retries = 0;; retries++) {
    try {
        return doSomething();
    } catch (SomeException e) {
        if (retries < 6) {
            continue;
        } else {
            throw e;
        }
    }
}
Meriton
fonte
Espere, por que não ter a condição dentro da declaração do loop for como: for (tentativas int = 0; tentativas <6; tentativas ++) ??
Didier A.
8
Porque eu só quero jogar a última tentativa e, portanto, o bloco catch precisa dessa condição, tornando a condição redundante.
22614 meriton
1
Eu não acho que continueé necessário lá .. E você pode simplesmente inverter a condição if.
Koray Tugay
19

Embora try/catchinto whileseja uma estratégia bem conhecida e boa, quero sugerir uma ligação recursiva:

void retry(int i, int limit) {
    try {

    } catch (SomeException e) {
        // handle exception
        if (i >= limit) {
            throw e;  // variant: wrap the exception, e.g. throw new RuntimeException(e);
        }
        retry(i++, limit);
    }
}
AlexR
fonte
41
Como a recursão é melhor que um loop para este caso de uso?
Dan
7
O rastreamento de pilha pode parecer um pouco estranho nesse caso, porque não limitcontaria o método que está sendo recorrente? Em oposição à versão loop, que vai jogar no nível 'original' ...
Clockwork-Muse
7
Certamente parece elegante no papel, mas não tenho certeza se a recursão é a abordagem certa de alguma forma.
Thomas
3
Eu não entendo por que recursão aqui também. Enfim, acho que poderia ser simplificado para:void retry(int times) { (...) if (times==0) throw w; retry(times--);
sinuhepop
8
É uma prática ruim usar a recursão como um substituto para a mera iteração. A recursão é para uso quando você deseja pressionar e exibir alguns dados.
Marquês de Lorne
19

Seu cenário exato tratado pelo Failsafe :

RetryPolicy retryPolicy = new RetryPolicy()
  .retryOn(NearlyUnexpectedException.class);

Failsafe.with(retryPolicy)
  .onRetry((r, f) -> fix_the_problem())
  .run(() -> some_instruction());

Bem simples.

Jonathan
fonte
5
biblioteca muito boa.
Maksim
para aqueles que se perguntam, você precisará disso em suas dependências gradle - compile 'net.jodah: failafe: 1.1.0'
Shreyas
18

Você pode usar anotações AOP e Java em jcabi-aspect (eu sou desenvolvedor):

@RetryOnFailure(attempts = 3, delay = 5)
public String load(URL url) {
  return url.openConnection().getContent();
}

Você também pode usar @Loggablee @LogExceptionanotações.

yegor256
fonte
Uau ! Parece fantasia! :)
Alind Billore
Deve ser a melhor resposta.
Mohamed Taher Alrefaie 4/03/16
2
existe uma maneira de "corrigir" o erro quando a tentativa falhar (algumas adoções podem corrigir a próxima tentativa)? veja a pergunta: fix_the_problem();no bloco catch
warch
Dada a quantidade de problemas em aberto e o tempo decorrido para que os bugs reconhecidos não sejam corrigidos, eu não confiaria nessa biblioteca.
Michael Lihs
6

A maioria dessas respostas é essencialmente a mesma. A minha também é, mas essa é a forma que eu gosto

boolean completed = false;
Throwable lastException = null;
for (int tryCount=0; tryCount < config.MAX_SOME_OPERATION_RETRIES; tryCount++)
{
    try {
        completed = some_operation();
        break;
    }
    catch (UnlikelyException e) {
        lastException = e;
        fix_the_problem();
    }
}
if (!completed) {
    reportError(lastException);
}
Stephen P
fonte
Uma desvantagem é que você também liga fix_the_problemapós a última tentativa. Isso pode ser uma operação cara e pode levar algum tempo.
Joachim Sauer
2
@JoachimSauer True. Você poderia if (tryCount < max) fix()- mas esse é o formato de uma abordagem geral; os detalhes dependeriam de um caso específico. Há também um secador de goiaba que eu estou olhando.
Stephen P
4

Spring AOP e solução baseada em anotação:

Uso ( @RetryOperationé nossa anotação personalizada para o trabalho):

@RetryOperation(retryCount = 1, waitSeconds = 10)
boolean someMethod() throws Exception {
}

Para isso, precisaremos de duas coisas: 1. uma interface de anotação e 2. um aspecto de primavera. Aqui está uma maneira de implementar estes:

A interface de anotação:

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RetryOperation {
    int retryCount();
    int waitSeconds();
}

O aspecto da primavera:

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;

@Aspect @Component 
public class RetryAspect {

    private static final Logger LOGGER = LoggerFactory.getLogger(RetryAspect.class);

    @Around(value = "@annotation(RetryOperation)")
    public Object retryOperation(ProceedingJoinPoint joinPoint) throws Throwable {

        Object response = null;
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        RetryOperation annotation = method.getAnnotation(RetryOperation.class);
        int retryCount = annotation.retryCount();
        int waitSeconds = annotation.waitSeconds();
        boolean successful = false;

        do {
            try {
                response = joinPoint.proceed();
                successful = true;
            } catch (Exception ex) {
                LOGGER.info("Operation failed, retries remaining: {}", retryCount);
                retryCount--;
                if (retryCount < 0) {
                    throw ex;
                }
                if (waitSeconds > 0) {
                    LOGGER.info("Waiting for {} second(s) before next retry", waitSeconds);
                    Thread.sleep(waitSeconds * 1000l);
                }
            }
        } while (!successful);

        return response;
    }
}
Vivek Sethi
fonte
3

Use um whileloop com statussinalizador local . Inicialize o sinalizador como falsee defina-o truequando a operação for bem-sucedida, por exemplo, abaixo:

  boolean success  = false;
  while(!success){
     try{ 
         some_instruction(); 
         success = true;
     } catch (NearlyUnexpectedException e){
       fix_the_problem();
     }
  }

Isso continuará tentando novamente até que seja bem-sucedido.

Se você deseja tentar novamente apenas um certo número de vezes, use também um contador:

  boolean success  = false;
  int count = 0, MAX_TRIES = 10;
  while(!success && count++ < MAX_TRIES){
     try{ 
         some_instruction(); 
         success = true;
     } catch (NearlyUnexpectedException e){
       fix_the_problem();
     }
  }
  if(!success){
    //It wasn't successful after 10 retries
  }

Isso tentará no máximo 10 vezes, se não for bem-sucedido até então, um sairá se for bem-sucedido antes da mão.

Yogendra Singh
fonte
Em vez de procurar !successno seu tempo, você pode simplesmente sair do tempo em que o sucesso é verdadeiro.
precisa
1
@RohitJain: Parece mais limpo para mim.
Yogendra Singh
@YogendraSingh .. Strange. como você não está modificando seu successlugar em seu catch. Portanto, parece redundante verificar isso a cada execução catch.
precisa
@RohitJain: Catch está apenas corrigindo os dados. Ele voltará e executará a instrução novamente. Se for bem-sucedido, ele modificará o success. Experimente.
Yogendra Singh
3

Esta é uma pergunta antiga, mas uma solução ainda é relevante. Aqui está minha solução genérica no Java 8 sem usar nenhuma biblioteca de terceiros:

public interface RetryConsumer<T> {
    T evaluate() throws Throwable;
}
public interface RetryPredicate<T> {
    boolean shouldRetry(T t);
}
public class RetryOperation<T> {
    private RetryConsumer<T> retryConsumer;
    private int noOfRetry;
    private int delayInterval;
    private TimeUnit timeUnit;
    private RetryPredicate<T> retryPredicate;
    private List<Class<? extends Throwable>> exceptionList;

    public static class OperationBuilder<T> {
        private RetryConsumer<T> iRetryConsumer;
        private int iNoOfRetry;
        private int iDelayInterval;
        private TimeUnit iTimeUnit;
        private RetryPredicate<T> iRetryPredicate;
        private Class<? extends Throwable>[] exceptionClasses;

        private OperationBuilder() {
        }

        public OperationBuilder<T> retryConsumer(final RetryConsumer<T> retryConsumer) {
            this.iRetryConsumer = retryConsumer;
            return this;
        }

        public OperationBuilder<T> noOfRetry(final int noOfRetry) {
            this.iNoOfRetry = noOfRetry;
            return this;
        }

        public OperationBuilder<T> delayInterval(final int delayInterval, final TimeUnit timeUnit) {
            this.iDelayInterval = delayInterval;
            this.iTimeUnit = timeUnit;
            return this;
        }

        public OperationBuilder<T> retryPredicate(final RetryPredicate<T> retryPredicate) {
            this.iRetryPredicate = retryPredicate;
            return this;
        }

        @SafeVarargs
        public final OperationBuilder<T> retryOn(final Class<? extends Throwable>... exceptionClasses) {
            this.exceptionClasses = exceptionClasses;
            return this;
        }

        public RetryOperation<T> build() {
            if (Objects.isNull(iRetryConsumer)) {
                throw new RuntimeException("'#retryConsumer:RetryConsumer<T>' not set");
            }

            List<Class<? extends Throwable>> exceptionList = new ArrayList<>();
            if (Objects.nonNull(exceptionClasses) && exceptionClasses.length > 0) {
                exceptionList = Arrays.asList(exceptionClasses);
            }
            iNoOfRetry = iNoOfRetry == 0 ? 1 : 0;
            iTimeUnit = Objects.isNull(iTimeUnit) ? TimeUnit.MILLISECONDS : iTimeUnit;
            return new RetryOperation<>(iRetryConsumer, iNoOfRetry, iDelayInterval, iTimeUnit, iRetryPredicate, exceptionList);
        }
    }

    public static <T> OperationBuilder<T> newBuilder() {
        return new OperationBuilder<>();
    }

    private RetryOperation(RetryConsumer<T> retryConsumer, int noOfRetry, int delayInterval, TimeUnit timeUnit,
                           RetryPredicate<T> retryPredicate, List<Class<? extends Throwable>> exceptionList) {
        this.retryConsumer = retryConsumer;
        this.noOfRetry = noOfRetry;
        this.delayInterval = delayInterval;
        this.timeUnit = timeUnit;
        this.retryPredicate = retryPredicate;
        this.exceptionList = exceptionList;
    }

    public T retry() throws Throwable {
        T result = null;
        int retries = 0;
        while (retries < noOfRetry) {
            try {
                result = retryConsumer.evaluate();
                if (Objects.nonNull(retryPredicate)) {
                    boolean shouldItRetry = retryPredicate.shouldRetry(result);
                    if (shouldItRetry) {
                        retries = increaseRetryCountAndSleep(retries);
                    } else {
                        return result;
                    }
                } else {
                    // no retry condition defined, no exception thrown. This is the desired result.
                    return result;
                }
            } catch (Throwable e) {
                retries = handleException(retries, e);
            }
        }
        return result;
    }

    private int handleException(int retries, Throwable e) throws Throwable {
        if (exceptionList.contains(e.getClass()) || (exceptionList.isEmpty())) {
            // exception is excepted, continue retry.
            retries = increaseRetryCountAndSleep(retries);
            if (retries == noOfRetry) {
                // evaluation is throwing exception, no more retry left. Throw it.
                throw e;
            }
        } else {
            // unexpected exception, no retry required. Throw it.
            throw e;
        }
        return retries;
    }

    private int increaseRetryCountAndSleep(int retries) {
        retries++;
        if (retries < noOfRetry && delayInterval > 0) {
            try {
                timeUnit.sleep(delayInterval);
            } catch (InterruptedException ignore) {
                Thread.currentThread().interrupt();
            }
        }
        return retries;
    }
}

Vamos ter um caso de teste como:

@Test
public void withPredicateAndException() {
    AtomicInteger integer = new AtomicInteger();
    try {
        Integer result = RetryOperation.<Integer>newBuilder()
                .retryConsumer(() -> {
                    int i = integer.incrementAndGet();
                    if (i % 2 == 1) {
                        throw new NumberFormatException("Very odd exception");
                    } else {
                        return i;
                    }
                })
                .noOfRetry(10)
                .delayInterval(10, TimeUnit.MILLISECONDS)
                .retryPredicate(value -> value <= 6)
                .retryOn(NumberFormatException.class, EOFException.class)
                .build()
                .retry();
        Assert.assertEquals(8, result.intValue());
    } catch (Throwable throwable) {
        Assert.fail();
    }
}
GirishB
fonte
boa ideia, um construtor para isso!
HankTheTank 19/07/19
2

Uma maneira simples de resolver o problema seria agrupar a tentativa / captura em um loop while e manter uma contagem. Dessa forma, você pode impedir um loop infinito verificando uma contagem em relação a outra variável enquanto mantém um log de suas falhas. Não é a solução mais requintada, mas funcionaria.

Jordan Kaye
fonte
1

Use um tempo para projetar o bloco de repetição.

boolean successful = false;
int maxTries = 3;
do{
  try {
    something();
    success = true;
  } catch(Me ifUCan) {
    maxTries--;
  }
} while (!successful || maxTries > 0)
Rahul Malhotra
fonte
2
O código deve lançar a exceção original se frustrada
lilalinux
1

Caso seja útil, mais algumas opções a considerar, todas reunidas (arquivo de parada em vez de novas tentativas, suspensão, continuar um loop maior), tudo isso possivelmente útil.

 bigLoop:
 while(!stopFileExists()) {
    try {
      // do work
      break;
    }
    catch (ExpectedExceptionType e) {

       // could sleep in here, too.

       // another option would be to "restart" some bigger loop, like
       continue bigLoop;
    }
    // ... more work
}
rogerdpack
fonte
Para baixo eleitores, por favor, deixe comentários sobre o porquê, obrigado!
Rogerdpack 12/05
1
É uma pura ignorância recusar o voto e não citar um motivo.
Xploreraj
dormir lá não é óbvio desde o loop while não esperaria
João Pimentel Ferreira
1

Você pode usar https://github.com/bnsd55/RetryCatch

Exemplo:

RetryCatch retryCatchSyncRunnable = new RetryCatch();
        retryCatchSyncRunnable
                // For infinite retry times, just remove this row
                .retryCount(3)
                // For retrying on all exceptions, just remove this row
                .retryOn(ArithmeticException.class, IndexOutOfBoundsException.class)
                .onSuccess(() -> System.out.println("Success, There is no result because this is a runnable."))
                .onRetry((retryCount, e) -> System.out.println("Retry count: " + retryCount + ", Exception message: " + e.getMessage()))
                .onFailure(e -> System.out.println("Failure: Exception message: " + e.getMessage()))
                .run(new ExampleRunnable());

Em vez de new ExampleRunnable()você pode passar sua própria função anônima.

bnsd55
fonte
1

Se nem todas as exceções justificarem uma nova tentativa, apenas algumas. E se pelo menos uma tentativa tiver que ser feita, aqui está um método utilitário alternativo:

void runWithRetry(Runnable runnable, Class<Exception> exClass, int maxRetries) {
        Exception err = null;
        do {
            maxRetries--;
            try {
                runnable.run();
                err = null;
            } catch (Exception e) {
                if(exClass.isAssignableFrom(e.getClass())){
                    err = e;
                }else {
                    throw e;
                }
            }
        } while (err != null && maxRetries > 0);

        if (err != null) {
            throw err;
        }
    }

Uso:

    runWithRetry(() -> {
       // do something
    }, TimeoutException.class, 5)
SD
fonte
0

Tudo o que um Try-Catch faz é permitir que seu programa falhe normalmente. Em uma instrução catch, você geralmente tenta registrar o erro e, se necessário, reverter as alterações.

bool finished = false;

while(finished == false)
{
    try
    {
        //your code here
        finished = true
    }
    catch(exception ex)
    {
        log.error("there was an error, ex");
    }
}
Sam eu sou diz Reinstate Monica
fonte
você quer dizer em oposição a (!finished)?
Sam I am diz Restabelecer Monica
1
@RohitJain parece muito while(finished). Eu prefiro usar a versão mais detalhada.
Sam I am diz Restabelecer Monica
3
Como diabos se while(!finished)parece while (finished)??
Rohit Jain
@Rohit Porque é apenas um caractere diferente. Todos eles são compilados até a mesma coisa. Em C #, eu uso um método de extensão String IsPopulated()que apenas retorna !IsNullOrEmpty()para garantir que minha intenção seja compreendida por todos os desenvolvedores.
Michael Blackburn
0

Eu sei que já existem muitas respostas semelhantes aqui, e as minhas não são muito diferentes, mas eu as publicarei de qualquer maneira, porque lida com um caso / problema específico.

Às vezes, ao lidar com o facebook Graph APIin, PHPvocê recebe um erro, mas tentar novamente a mesma coisa imediatamente dará um resultado positivo (por várias razões mágicas da Internet que estão além do escopo desta pergunta). Nesse caso, não há necessidade de corrigir nenhum erro, mas simplesmente tente novamente porque houve algum tipo de "erro no facebook".

Este código é usado imediatamente após a criação de uma sessão no facebook:

//try more than once because sometimes "facebook error"
$attempt = 3;
while($attempt-- > 0)
{
    // To validate the session:
    try 
    {
        $facebook_session->validate();
        $attempt = 0;
    } 
    catch (Facebook\FacebookRequestException $ex)
    {
        // Session not valid, Graph API returned an exception with the reason.
        if($attempt <= 0){ echo $ex->getMessage(); }
    } 
    catch (\Exception $ex) 
    {
        // Graph API returned info, but it may mismatch the current app or have expired.
        if($attempt <= 0){ echo $ex->getMessage(); }
    }
}

Além disso, ao contar o forloop até zero ( $attempt--), é muito fácil alterar o número de tentativas no futuro.

KnightHawk
fonte
0

A seguir, é minha solução com uma abordagem muito simples!

               while (true) {
                    try {
                        /// Statement what may cause an error;
                        break;
                    } catch (Exception e) {

                    }
                }
David Kayo
fonte
1
veja a resposta de @Rohit Jain, que é mais específica e não um loop infinito em casos negativos.
Chandra Shekhar
0

Não tenho certeza se essa é a maneira "profissional" de fazer isso e não tenho certeza se ela funciona para tudo.

boolean gotError = false;

do {
    try {
        // Code You're Trying
    } catch ( FileNotFoundException ex ) {
        // Exception
        gotError = true;
    }
} while ( gotError = true );
Josh
fonte
0

Aqui, uma abordagem reutilizável e mais genérica para Java 8+ que não requer bibliotecas externas:

public interface IUnreliable<T extends Exception>
{
    void tryRun ( ) throws T;
}

public static <T extends Exception> void retry (int retryCount, IUnreliable<T> runnable) throws T {
    for (int retries = 0;; retries++) {
        try {
            runnable.tryRun();
            return;
        } catch (Exception e) {
            if (retries < retryCount) {
                continue;
            } else {
                throw e;
            }
        }
    }
}

Uso:

@Test
public void demo() throws IOException {
    retry(3, () -> {
        new File("/tmp/test.txt").createNewFile();
    });
}
Jonas_Hess
fonte
0

O problema com as soluções restantes é que, a função correspondente tenta continuamente sem um intervalo de tempo intermediário, sobrecarregando a pilha.

Por que não apenas trycada segundo e ad eternum ?

Aqui, uma solução usando setTimeoute uma função recursiva:

(function(){
  try{
    Run(); //tries for the 1st time, but Run() as function is not yet defined
  }
  catch(e){
    (function retry(){
      setTimeout(function(){
        try{
          console.log("trying...");
          Run();
          console.log("success!");
        }
        catch(e){
          retry(); //calls recursively
        }
      }, 1000); //tries every second
    }());
  }
})();



//after 5 seconds, defines Run as a global function
var Run;
setTimeout(function(){
  Run = function(){};
}, 5000);

Substitua a função Run()pela função ou código que você deseja substituir a trycada segundo.

João Pimentel Ferreira
fonte
0

Experimente usar a anotação springs @Retryable, o método abaixo tentará novamente por 3 tentativas quando ocorrer RuntimeException

@Retryable(maxAttempts=3,value= {RuntimeException.class},backoff = @Backoff(delay = 500))
public void checkSpringRetry(String str) {
    if(StringUtils.equalsIgnoreCase(str, "R")) {
        LOGGER.info("Inside retry.....!!");
        throw new RuntimeException();
    }
}
NKR
fonte
0

Abaixo do snippet, execute algum snippet de código. Se houver algum erro ao executar o trecho de código, durma por milissegundos e tente novamente. Link de referência .

public void retryAndExecuteErrorProneCode(int noOfTimesToRetry, CodeSnippet codeSnippet, int sleepTimeInMillis)
  throws InterruptedException {

 int currentExecutionCount = 0;
 boolean codeExecuted = false;

 while (currentExecutionCount < noOfTimesToRetry) {
  try {
   codeSnippet.errorProneCode();
   System.out.println("Code executed successfully!!!!");
   codeExecuted = true;
   break;
  } catch (Exception e) {
   // Retry after 100 milliseconds
   TimeUnit.MILLISECONDS.sleep(sleepTimeInMillis);
   System.out.println(e.getMessage());
  } finally {
   currentExecutionCount++;
  }
 }

 if (!codeExecuted)
  throw new RuntimeException("Can't execute the code within given retries : " + noOfTimesToRetry);
}
Hari Krishna
fonte
0

Aqui está minha solução semelhante a algumas outras que podem envolver uma função, mas permite que você obtenha o valor de retorno das funções, se tiver êxito.

    /**
     * Wraps a function with retry logic allowing exceptions to be caught and retires made.
     *
     * @param function the function to retry
     * @param maxRetries maximum number of retires before failing
     * @param delay time to wait between each retry
     * @param allowedExceptionTypes exception types where if caught a retry will be performed
     * @param <V> return type of the function
     * @return the value returned by the function if successful
     * @throws Exception Either an unexpected exception from the function or a {@link RuntimeException} if maxRetries is exceeded
     */
    @SafeVarargs
    public static <V> V runWithRetriesAndDelay(Callable<V> function, int maxRetries, Duration delay, Class<? extends Exception>... allowedExceptionTypes) throws Exception {
        final Set<Class<? extends Exception>> exceptions = new HashSet<>(Arrays.asList(allowedExceptionTypes));
        for(int i = 1; i <= maxRetries; i++) {
            try {
                return function.call();
            } catch (Exception e) {
                if(exceptions.contains(e.getClass())){
                    // An exception of an expected type
                    System.out.println("Attempt [" + i + "/" + maxRetries + "] Caught exception [" + e.getClass() + "]");
                    // Pause for the delay time
                    Thread.sleep(delay.toMillis());
                }else {
                    // An unexpected exception type
                    throw e;
                }
            }
        }
        throw new RuntimeException(maxRetries + " retries exceeded");
    }
James Mudd
fonte