Come si implementa un re-try-catch?


203

Try-catch ha lo scopo di aiutare nella gestione delle eccezioni. Ciò significa che in qualche modo aiuterà il nostro sistema a essere più robusto: prova a recuperare da un evento imprevisto.

Sospettiamo che possa accadere qualcosa durante l'esecuzione e l'istruzione (invio di un messaggio), quindi viene racchiuso nel tentativo. Se succede qualcosa di quasi inaspettato, possiamo fare qualcosa: scriviamo il trucco. Non credo che abbiamo chiamato solo per registrare l'eccezione. Credo che il blocco catch abbia lo scopo di darci l'opportunità di recuperare dall'errore.

Ora, supponiamo che ci riprendiamo dall'errore perché potremmo correggere ciò che era sbagliato. Potrebbe essere molto bello fare un nuovo tentativo:

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

Questo cadrà rapidamente nel ciclo eterno, ma diciamo che il problema fix_the_ restituisce true, quindi riproviamo. Dato che non esiste nulla di simile in Java, come risolveresti questo problema? Quale sarebbe il tuo miglior codice di progettazione per risolvere questo?

Questa è una domanda filosofica, dato che so già che cosa sto chiedendo non è direttamente supportato da Java.


5
Che tipo di eccezione è quella?
Bhesh Gurung,

23
Mi piace il nome della tua eccezione. ;)
Rohit Jain,

In realtà, non ci sono molte eccezioni da cui è possibile recuperare. Devo ammettere che la mia motivazione iniziale non è stata una vera eccezione, ma un modo per evitare un se ciò non accadrà quasi mai: provo a farlo remove()da una java.util.Queue, che torce e InvalidElementExceptionquando la coda è vuota. Invece di chiedere se è vuoto, cerco le azioni in un try-catch (che sotto concorrenza diventa obbligatorio anche con il precedente if). In tal caso, nel catchblocco chiederei di riempire la coda con più elementi e quindi riprovare. Ecco.
Andres Farias,

1
Vedo che il solito modo di farlo sarebbe per l'accesso al DB, se la connessione non è riuscita a riconnettersi, se fallisce, getta un'eccezione importante, altrimenti ritenta nuovamente la chiamata. Come è stato detto, potremmo farlo in un ciclo con un segno di spunta in fondo se (errore <> 0) quindi tornare indietro altrimenti rompere;
Theresa Forster,

Risposte:


305

Devi racchiudere il tuo try-catchinterno in un whileciclo come questo: -

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

Ho preso counte maxTriesper evitare di imbattermi in un ciclo infinito, nel caso in cui l'eccezione continui a verificarsi nel tuo try block.


3
All'inizio ho pensato a qualcosa del genere, senza i maxTries. Grazie per la risposta!
Andres Farias,

6
@AndresFarias .. Sì, il punto più importante in questa risposta è includere a maxTries. Altrimenti si imbatterà in un infinite looputente che fornisce continuamente input errati e quindi non si chiuderà. Di niente però. :)
Rohit Jain,

grazie per questo - mi ha appena salvato dal dover scrivere del codice molto nodoso!
David Holiday,

2
È possibile aggiungere la funzione Thread.sleep () all'interno del fermo qui. Perché in alcuni casi, come aspettare la risposta della pagina nella libreria Selenium che è diventata critica. Grazie.
Suat Atan PhD,

2
Funziona alla grande! Per i principianti: se ottieni un ciclo infinito positivo, controlla se hai aggiunto "break;" alla fine nel blocco "prova".
Krzysztof Walczewski,

59

Soluzione "enterprisy" obbligatoria:

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 chiamare:

OperationHelper.doWithRetry(5, new Operation() {
    @Override public void doIt() {
        //do some stuff
    }
    @Override public void handleException(Exception cause) {
        //recover from the Exception
    }
});

6
Dovresti rilanciare l'eccezione se l'ultimo tentativo fallisce, come fatto nelle altre risposte fornite.
cvacca,

35

Come al solito, il miglior design dipende dalle circostanze particolari. Di solito però scrivo qualcosa del tipo:

for (int retries = 0;; retries++) {
    try {
        return doSomething();
    } catch (SomeException e) {
        if (retries < 6) {
            continue;
        } else {
            throw e;
        }
    }
}

Aspetta, perché non avere la condizione all'interno della dichiarazione del ciclo for come: for (int retries = 0; retries <6; retries ++) ??
Didier A.

8
Perché voglio solo lanciare l'ultimo tentativo, e quindi il blocco catch ha bisogno di quella condizione, rendendo superflua la condizione nel for.
Meriton,

1
Non penso che continuesia necessario lì .. E puoi semplicemente capovolgere la condizione if.
Koray Tugay,

19

Sebbene try/catchin whilesia una strategia ben nota e buona, voglio suggerirti una chiamata ricorsiva:

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

41
In che modo la ricorsione è migliore di un ciclo per questo caso d'uso?
Dan,

7
La traccia dello stack potrebbe sembrare un po 'strana su questo, perché non avrebbe limitconteggiato il metodo che si sta ripetendo? A differenza della versione loop, che verrà lanciata al livello "originale" ...
Clockwork-Muse,

7
Certo sembra elegante sulla carta ma non sono sicuro che la ricorsione sia in qualche modo l'approccio giusto.
Thomas,

3
Non capisco perché anche la ricorsione qui. Ad ogni modo, penso che potrebbe essere semplificato per:void retry(int times) { (...) if (times==0) throw w; retry(times--);
sinuhepop

8
È una cattiva pratica usare la ricorsione come sostituto della semplice iterazione. La ricorsione è da utilizzare quando si desidera inviare e inserire alcuni dati.
Marchese di Lorne,

19

Lo scenario esatto gestito tramite Failsafe :

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

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

Abbastanza semplice.


5
biblioteca molto bella.
Maksim,

per quelli che si chiedono, ne avrai bisogno nelle tue dipendenze elementari - compila 'net.jodah: fail-safe: 1.1.0'
Shreyas,

18

Puoi usare le annotazioni AOP e Java da aspetti jcabi (sono uno sviluppatore):

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

È inoltre possibile utilizzare @Loggablee @LogExceptionannotazioni.


Wow ! Sembra fantasia! :)
Alind Billore,

Dovrebbe essere la risposta migliore.
Mohamed Taher Alrefaie

2
c'è un modo per "correggere" l'errore quando il tentativo fallisce (alcune adozioni che potrebbero risolvere il tentativo successivo)? vedi domanda: fix_the_problem();nel blocco delle catture
warch

Considerata la quantità di problemi aperti e il tempo trascorso per i bug riconosciuti non corretti, non farei affidamento su questa libreria.
Michael Lihs,

6

Molte di queste risposte sono essenzialmente le stesse. Anche il mio è, ma questa è la forma che mi piace

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

Uno svantaggio è che si chiama anche fix_the_problemdopo l'ultimo tentativo. Che potrebbe essere un'operazione costosa e potrebbe perdere tempo.
Joachim Sauer,

2
@JoachimSauer True. Potresti if (tryCount < max) fix()- ma questo è il formato di un approccio generale; i dettagli dipenderebbero da un caso specifico. C'è anche un Retryer a base di guava che ho visto.
Stephen P

4

Spring AOP e soluzione basata su annotazioni:

Utilizzo ( @RetryOperationè la nostra annotazione personalizzata per il lavoro):

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

A tal fine avremo bisogno di due cose: 1. un'interfaccia di annotazione e 2. un aspetto primaverile. Ecco un modo per implementarli:

L'interfaccia di annotazione:

import java.lang.annotation.*;

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

L'aspetto primaverile:

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

3

Utilizzare un whileloop con statusflag locale . Inizializza il flag come falsee impostalo su truequando l'operazione ha esito positivo, ad es. Di seguito:

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

Questo continuerà a riprovare fino a quando avrà successo.

Se si desidera riprovare solo un determinato numero di volte, utilizzare anche un contatore:

  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
  }

Questo proverà al massimo 10 volte se non ha esito positivo fino a quel momento verrà chiuso in caso di esito positivo.


Invece di controllare per !successun po ', puoi semplicemente uscire quando il successo è vero.
Rohit Jain,

1
@RohitJain: mi sembra più pulito.
Yogendra Singh,

@YogendraSingh .. Strange. poiché non stai modificando il tuo da successnessuna parte nel tuo catch. Quindi sembra ridondante verificarlo, ad ogni ciclo di catch.
Rohit Jain,

@RohitJain: Catch sta solo correggendo i dati. Tornerà indietro ed eseguirà nuovamente la dichiarazione. In caso di successo, modificherà il success. Provalo.
Yogendra Singh,

3

Questa è una vecchia domanda ma una soluzione è ancora pertinente. Ecco la mia soluzione generica in Java 8 senza utilizzare alcuna libreria di terze parti:

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

Facciamo un caso di prova come:

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

bella idea, un costruttore per quello!
HankTheTank,

2

Un modo semplice per risolvere il problema sarebbe quello di racchiudere il ciclo try / catch in un ciclo while e mantenere un conteggio. In questo modo è possibile impedire un ciclo infinito controllando un conteggio rispetto ad altre variabili mantenendo un registro degli errori. Non è la soluzione più squisita, ma funzionerebbe.


1

Usa un do-while per progettare il blocco re-try.

boolean successful = false;
int maxTries = 3;
do{
  try {
    something();
    success = true;
  } catch(Me ifUCan) {
    maxTries--;
  }
} while (!successful || maxTries > 0)

2
Il codice dovrebbe generare l'eccezione originale in caso di esito
negativo

1

Nel caso sia utile, un paio di opzioni in più da considerare, tutte messe insieme (stopfile invece di tentativi, sleep, continua ad anello più ampio) tutte possibilmente utili.

 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
}

Per favore, per favore, lasciate commenti sul perché, grazie!
rogerdpack,

1
Questa è una pura ignoranza da sottovalutare e non citare una ragione.
xploreraj,

dormire lì non è ovvio poiché il ciclo while non aspetterebbe
João Pimentel Ferreira,

1

Puoi usare https://github.com/bnsd55/RetryCatch

Esempio:

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

Invece di new ExampleRunnable()te puoi passare la tua funzione anonima.


1

Se non tutte le eccezioni giustificano un nuovo tentativo, solo alcune. E se è necessario eseguire almeno un tentativo, ecco un metodo di utilità 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)

0

Tutto ciò che Try-Catch fa è consentire al tuo programma di fallire con grazia. In una dichiarazione catch, in genere si tenta di registrare l'errore e, se necessario, è possibile ripristinare le modifiche.

bool finished = false;

while(finished == false)
{
    try
    {
        //your code here
        finished = true
    }
    catch(exception ex)
    {
        log.error("there was an error, ex");
    }
}

intendi al contrario (!finished)?
Sam, sono io, reintegrate Monica il

1
@RohitJain sembra troppo simile while(finished). Preferisco usare la versione più dettagliata.
Sam, lo so, ripristina Monica il

3
Come mai while(!finished)sembra while (finished)??
Rohit Jain,

@Rohit Perché è solo un personaggio diverso. Vengono tutti compilati nella stessa cosa. In C #, utilizzo un metodo di estensione String IsPopulated()che ritorna !IsNullOrEmpty()per garantire che il mio intento sia compreso da tutti gli sviluppatori.
Michael Blackburn,

0

So che ci sono già molte risposte simili qui, e la mia non è molto diversa, ma la posterò comunque perché si occupa di un caso / problema specifico.

Quando si ha a che fare con facebook Graph APIa PHPvolte si ottiene un errore, ma riprovare immediatamente la stessa cosa darà un risultato positivo (per varie magiche ragioni di Internet che vanno oltre lo scopo di questa domanda). In questo caso non è necessario riparare alcun errore, ma semplicemente riprovare perché si è verificato un "errore di Facebook".

Questo codice viene utilizzato immediatamente dopo aver creato una sessione 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(); }
    }
}

Inoltre, avendo il forconto alla rovescia fino a zero ( $attempt--), è abbastanza facile cambiare il numero di tentativi in ​​futuro.


0

Di seguito è la mia soluzione con un approccio molto semplice!

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

                    }
                }

1
guarda la risposta Jain @Rohit che è più specifica e non un ciclo infinito in casi negativi.
Chandra Shekhar,

0

Non sono sicuro che questo sia il modo "Professionale" per farlo e non sono del tutto sicuro che funzioni per tutto.

boolean gotError = false;

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


0

Ecco un approccio riutilizzabile e più generico per Java 8+ che non richiede librerie esterne:

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

0

Il problema con le restanti soluzioni è che la funzione corrispondente tenta continuamente senza un intervallo di tempo intermedio, in modo da inondare lo stack.

Perché non solo trying solo ogni secondo e ad eternum ?

Ecco una soluzione che utilizza setTimeoute una funzione ricorsiva:

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

Sostituisci la funzione Run()con la funzione o il codice che desideri ripetere tryogni secondo.


0

Fai una prova usando l'annotazione molle @Retryable, il metodo seguente riproverà per 3 tentativi quando si verifica 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();
    }
}

0

Sotto lo snippet esegui qualche frammento di codice. Se riscontri errori durante l'esecuzione dello snippet di codice, dormi per M millisecondi e riprova. Link di riferimento .

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

0

Ecco la mia soluzione simile ad altre che può racchiudere una funzione, ma ti permette di ottenere il valore di ritorno delle funzioni, se succede.

    /**
     * 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");
    }
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.