¿Cómo implementas un re-try-catch?

203

Try-catch está destinado a ayudar en el manejo de excepciones. Esto significa de alguna manera que ayudará a nuestro sistema a ser más robusto: intente recuperarse de un evento inesperado.

Sospechamos que algo podría suceder al ejecutar e instruir (enviar un mensaje), por lo que queda encerrado en el intento. Si sucede algo casi inesperado, podemos hacer algo: escribimos la captura. No creo que hayamos llamado para registrar la excepción. Creo que el bloque catch está destinado a darnos la oportunidad de recuperarnos del error.

Ahora, digamos que nos recuperamos del error porque pudimos arreglar lo que estaba mal. Podría ser super agradable volver a intentarlo:

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

Esto caería rápidamente en el ciclo eterno, pero digamos que el fix_the_problem devuelve verdadero, luego volvemos a intentarlo. Dado que no existe tal cosa en Java, ¿cómo resolvería USTED este problema? ¿Cuál sería su mejor código de diseño para resolver esto?

Esto es como una pregunta filosófica, dado que ya sé que lo que estoy pidiendo no es compatible directamente con Java.

Andres Farias
fuente
55
¿Qué tipo de excepción es esa?
Bhesh Gurung
23
Sin embargo, me gusta el nombre de tu excepción. ;)
Rohit Jain
De hecho, no hay muchas excepciones de las que pueda recuperarse. Admito que mi motivación inicial no fue una excepción real, sino una forma de evitar que eso suceda casi nunca: trato de hacerlo remove()desde una java.util.Queue, lo que ocurre y InvalidElementExceptioncuando la cola está vacía. En lugar de preguntar si está vacío, rodeo las acciones en un try-catch (que bajo concurrencia se vuelve obligatorio incluso con el if anterior). En tal caso, en el catchbloque pediría rellenar la cola con más elementos y luego volver a intentarlo. Voila
Andres Farias el
1
Puedo ver que la forma habitual de hacerlo sería para el acceso a la base de datos, si la conexión ha fallado, vuelva a conectar, si falla, arroje una excepción importante; de ​​lo contrario, vuelva a intentar la llamada. Como se ha dicho, podríamos hacerlo en un bucle con una marca de verificación en la parte inferior si (error <> 0) luego regresa, de lo contrario se rompe;
Theresa Forster

Respuestas:

305

Necesitas encerrar tu try-catchinterior en un whilebucle 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;
    }
}

He tomado county maxTriespara evitar tropezar con un bucle infinito, en caso de que la excepción siga ocurriendo en su try block.

Rohit Jain
fuente
3
Al principio pensé en algo como esto, sin maxTries. ¡Gracias por la respuesta!
Andres Farias
66
@AndresFarias .. Sí, el punto más importante en esta respuesta es incluir a maxTries. De lo contrario, se encontrará con un infinite loopusuario si continuamente ingresa información incorrecta y, por lo tanto, no saldrá. De nada sin embargo. :)
Rohit Jain
gracias por esto, ¡simplemente me salvó de tener que escribir un código muy retorcido!
David Holiday
2
¿Es posible agregar la función Thread.sleep () dentro de la captura aquí? Porque en algunos casos, como esperar la respuesta de la página en la biblioteca Selenium, eso se volvió crítico. Gracias.
Suat Atan PhD
2
¡Funciona genial! Para principiantes: si obtienes un bucle infinito positivo, verifica si agregaste "break"; al final en el bloque "probar".
Krzysztof Walczewski
59

Solución obligatoria "emprendedora":

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

Y para llamar:

OperationHelper.doWithRetry(5, new Operation() {
    @Override public void doIt() {
        //do some stuff
    }
    @Override public void handleException(Exception cause) {
        //recover from the Exception
    }
});
ach
fuente
66
Debería volver a lanzar la excepción si falla el último intento, como se hizo en las otras respuestas dadas.
cvacca
35

Como de costumbre, el mejor diseño depende de las circunstancias particulares. Sin embargo, generalmente escribo algo como:

for (int retries = 0;; retries++) {
    try {
        return doSomething();
    } catch (SomeException e) {
        if (retries < 6) {
            continue;
        } else {
            throw e;
        }
    }
}
Meriton
fuente
Espere, ¿por qué no tener la condición dentro de la declaración de bucle for como: for (int retries = 0; retries <6; retries ++) ??
Didier A.
8
Porque solo quiero lanzar el último intento y, por lo tanto, el bloque catch necesita esa condición, lo que hace que la condición sea redundante.
meriton
1
No creo que continuesea ​​necesario allí ... Y simplemente puedes cambiar la condición if.
Koray Tugay
19

Aunque try/catchinto whilees una estrategia bien conocida y buena, quiero sugerirte una llamada 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
fuente
41
¿Cómo es la recursión mejor que un bucle para este caso de uso?
Dan
77
El seguimiento de la pila puede parecer un poco extraño en este caso, porque ¿no habría limitcontado el método que se está recurriendo? A diferencia de la versión en bucle, que se lanzará al nivel 'original' ...
Clockwork-Muse
77
Claro que se ve elegante en el papel, pero no estoy seguro de que la recursión sea el enfoque correcto de alguna manera.
Thomas
3
No entiendo por qué la recursividad aquí también. De todos modos, creo que podría simplificarse para:void retry(int times) { (...) if (times==0) throw w; retry(times--);
sinuhepop
8
Es una mala práctica usar la recursión como un sustituto de la mera iteración. La recursión es para usar cuando desea empujar y reventar algunos datos.
Marqués de Lorne
19

Su escenario exacto manejado a través de Failsafe :

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

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

Bastante simple.

Jonathan
fuente
55
Muy buena biblioteca.
Maksim
para aquellos que se preguntan, necesitarán esto en sus dependencias de gradle: compile 'net.jodah: failsafe: 1.1.0'
Shreyas el
18

Puede usar anotaciones AOP y Java de jcabi-aspectos (soy desarrollador):

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

También podría usar @Loggabley @LogExceptionanotaciones.

yegor256
fuente
Guauu ! Suena elegante! :)
Alind Billore
Debería ser la mejor respuesta.
Mohamed Taher Alrefaie
2
¿hay alguna manera de "arreglar" el error cuando falla el intento (algunas adopciones pueden arreglar el siguiente intento)? ver pregunta: fix_the_problem();en el bloque catch
warch
Dada la cantidad de problemas abiertos y el tiempo transcurrido para que los errores reconocidos no se solucionen, no confiaría en esta biblioteca.
Michael Lihs
6

La mayoría de estas respuestas son esencialmente las mismas. El mío también, pero esta es la forma que me gusta.

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
fuente
Un inconveniente es que también llamas fix_the_problemdespués del último intento. Esa podría ser una operación costosa y podría perder algo de tiempo.
Joachim Sauer
2
@JoachimSauer True. Podrías if (tryCount < max) fix(), pero este es el formato de un enfoque general; los detalles dependerán de un caso específico. También hay un Retryer a base de guayaba que he estado mirando.
Stephen P
4

Spring AOP y solución basada en anotaciones:

Uso ( @RetryOperationes nuestra anotación personalizada para el trabajo):

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

Necesitaremos dos cosas para lograr esto: 1. una interfaz de anotación, y 2. un aspecto de resorte. Aquí hay una forma de implementarlos:

La interfaz de anotación:

import java.lang.annotation.*;

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

El aspecto primaveral:

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
fuente
3

Use un whilebucle con statusbandera local . Inicialice el indicador como falsey configúrelo truecuando la operación sea exitosa, por ejemplo a continuación:

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

Esto volverá a intentarlo hasta que tenga éxito.

Si desea volver a intentarlo solo un cierto número de veces, use también un 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
  }

Esto intentará un máximo de 10 veces si no tiene éxito hasta entonces, y saldrá si tiene éxito de antemano.

Yogendra Singh
fuente
En lugar de verificar !successen su tiempo, puede salir de cuando el éxito es cierto.
Rohit Jain el
1
@RohitJain: Me parece más limpio.
Yogendra Singh
@YogendraSingh .. Extraño. ya que no estás modificando tu successen ninguna parte de tu catch. Por lo tanto, parece redundante comprobarlo, en cada ejecución de catch.
Rohit Jain
@RohitJain: Catch solo está corrigiendo los datos. Volverá y ejecutará la declaración nuevamente. Si tiene éxito, modificará el success. Pruébalo.
Yogendra Singh
3

Esta es una vieja pregunta, pero una solución sigue siendo relevante. Aquí está mi solución genérica en Java 8 sin usar ninguna biblioteca de terceros:

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

Tengamos un caso de prueba 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
fuente
buena idea, un constructor para eso!
HankTheTank
2

Una manera simple de resolver el problema sería envolver el try / catch en un ciclo while y mantener un conteo. De esta forma, podría evitar un bucle infinito al verificar un recuento con alguna otra variable mientras mantiene un registro de sus fallas. No es la solución más exquisita, pero funcionaría.

Jordan Kaye
fuente
1

Use un do-while para diseñar el bloque de reintento.

boolean successful = false;
int maxTries = 3;
do{
  try {
    something();
    success = true;
  } catch(Me ifUCan) {
    maxTries--;
  }
} while (!successful || maxTries > 0)
Rahul Malhotra
fuente
2
El código debería arrojar la excepción original si no tiene éxito
lilalinux
1

En caso de que sea útil, un par de opciones más a considerar, todas juntas (detener el archivo en lugar de reintentos, dormir, continuar con un ciclo más grande), todo posiblemente ú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
fuente
Abajo los votantes por favor dejen comentarios de por qué, ¡gracias!
rogerdpack
1
Esta es una pura ignorancia para rechazar y no citar una razón.
xploreraj
dormir allí no es obvio ya que el ciclo while no esperaría
João Pimentel Ferreira
1

Puede usar https://github.com/bnsd55/RetryCatch

Ejemplo:

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());

En lugar de new ExampleRunnable()usted, puede pasar su propia función anónima.

bnsd55
fuente
1

Si no todas las excepciones justifican un reintento, solo algunas. Y si hay que hacer al menos un intento, aquí hay un método de utilidad 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)
Dakota del Sur
fuente
0

Todo lo que un Try-Catch hace es permitir que su programa falle con gracia. En una declaración catch, generalmente intenta registrar el error y tal vez revierta los cambios si es necesario.

bool finished = false;

while(finished == false)
{
    try
    {
        //your code here
        finished = true
    }
    catch(exception ex)
    {
        log.error("there was an error, ex");
    }
}
Sam, soy, dice reinstalar a Mónica
fuente
¿quieres decir en lugar de (!finished)?
Sam, soy, dice Restablecer a Mónica el
1
@RohitJain se parece demasiado while(finished). Prefiero usar la versión más detallada.
Soy Sam, dice Reinstate Monica el
3
¿Cómo demonios se while(!finished)ve while (finished)?
Rohit Jain
@Rohit Porque es solo un personaje diferente. Todos se compilan a la misma cosa. En C #, utilizo un método de extensión de cadena IsPopulated()que simplemente regresa !IsNullOrEmpty()para garantizar que todos los desarrolladores entiendan mi intención.
Michael Blackburn
0

Sé que ya hay muchas respuestas similares aquí, y la mía no es muy diferente, pero la publicaré de todos modos porque trata un caso / problema específico.

Cuando se trata con la información, facebook Graph APIa PHPveces se produce un error, pero volver a intentarlo inmediatamente dará un resultado positivo (por varias razones mágicas de Internet que están fuera del alcance de esta pregunta). En este caso no hay necesidad de arreglar ningún error, sino simplemente intentarlo de nuevo porque hubo algún tipo de "error de Facebook".

Este código se usa inmediatamente después de crear una sesión de 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(); }
    }
}

Además, al hacer que el forciclo cuente hasta cero ( $attempt--), es bastante fácil cambiar el número de intentos en el futuro.

KnightHawk
fuente
0

¡La siguiente es mi solución con un enfoque muy simple!

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

                    }
                }
David Kayo
fuente
1
mire la respuesta de @Rohit Jain, que es más específica y no un bucle infinito en casos negativos.
Chandra Shekhar
0

No estoy seguro de si esta es la forma "profesional" de hacerlo y no estoy completamente seguro de si funciona para todo.

boolean gotError = false;

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

Aquí un enfoque reutilizable y más genérico para Java 8+ que no requiere 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
fuente
0

El problema con las soluciones restantes es que, la función correspondiente intenta continuamente sin un intervalo de tiempo intermedio, por lo tanto sobre inundando la pila.

¿Por qué no trysolo cada segundo y después del eterno ?

Aquí una solución usando setTimeouty una función 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);

Reemplace la función Run()por la función o el código que le gustaría volver trycada segundo.

João Pimentel Ferreira
fuente
0

Pruébelo utilizando los resortes @Anotaciones retribuibles, el siguiente método volverá a intentarlo por 3 intentos cuando se produzca 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
fuente
0

Debajo del fragmento ejecute un fragmento de código. Si tiene algún error al ejecutar el fragmento de código, duerma durante M milisegundos y vuelva a intentarlo. Referencia enlace .

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
fuente
0

Aquí está mi solución similar a algunas otras que pueden ajustar una función, pero le permite obtener el valor de retorno de las funciones, si tiene é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
fuente