Wie implementieren Sie einen Re-Try-Catch?

203

Try-Catch soll bei der Ausnahmebehandlung helfen. Dies bedeutet irgendwie, dass unser System dadurch robuster wird: Versuchen Sie, sich von einem unerwarteten Ereignis zu erholen.

Wir vermuten, dass bei der Ausführung und Anweisung (Senden einer Nachricht) etwas passieren könnte, sodass es in den Versuch eingeschlossen wird. Wenn etwas fast Unerwartetes passiert, können wir etwas tun: Wir schreiben den Haken. Ich glaube nicht, dass wir angerufen haben, um nur die Ausnahme zu protokollieren. Ich denke, der Catch-Block soll uns die Möglichkeit geben, den Fehler zu beheben.

Nehmen wir jetzt an, wir beheben den Fehler, weil wir das Problem beheben konnten. Es könnte super schön sein, es noch einmal zu versuchen:

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

Dies würde schnell in die ewige Schleife fallen, aber sagen wir, dass das Problem fix_the_problem true zurückgibt, dann versuchen wir es erneut. Wie würden SIE dieses Problem lösen, da es so etwas in Java nicht gibt? Was wäre Ihr bester Designcode, um dieses Problem zu lösen?

Dies ist wie eine philosophische Frage, da ich bereits weiß, dass das, wonach ich frage, von Java nicht direkt unterstützt wird.

Andres Farias
quelle
5
Was für eine Ausnahme ist das?
Bhesh Gurung
23
Ich mag den Namen Ihrer Ausnahme. ;)
Rohit Jain
In der Tat gibt es nicht viele Ausnahmen, von denen Sie sich erholen können. Ich gebe zu, dass meine anfängliche Motivation keine wirkliche Ausnahme war, sondern ein Weg, um zu vermeiden, dass dies fast nie passieren wird: Ich versuche es remove()von einem java.util.Queue, der durchstößt und InvalidElementExceptionwenn die Warteschlange leer ist. Anstatt zu fragen, ob es leer ist, umrunde ich die Aktionen in einem Try-Catch (der unter Parallelität auch mit dem vorherigen if obligatorisch wird). In einem solchen Fall catchwürde ich im Block darum bitten, die Warteschlange mit weiteren Elementen zu füllen und dann erneut zu versuchen. Voila.
Andres Farias
1
Ich kann sehen, dass der übliche Weg, dies zu tun, für den DB-Zugriff ist, wenn die Verbindung fehlgeschlagen ist, die Verbindung wiederherzustellen, wenn sie fehlschlägt, dann eine große Ausnahme auslösen, andernfalls den Anruf erneut versuchen. Wie gesagt, wir könnten es in einer Schleife mit einer Prüfung am unteren Rand tun, wenn (Fehler <> 0) dann zurückgehen, sonst brechen;
Theresa Forster

Antworten:

303

Sie müssen Ihr try-catchInneres in eine whileSchleife wie folgt einschließen : -

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

Ich habe genommen countund um maxTrieszu vermeiden, in eine Endlosschleife zu geraten, falls die Ausnahme in Ihrer weiterhin auftritt try block.

Rohit Jain
quelle
3
Ich dachte zuerst in so etwas, ohne die maxTries. Danke für die Antwort!
Andres Farias
6
@AndresFarias .. Ja, der wichtigste Punkt in dieser Antwort ist die Aufnahme von a maxTries. Andernfalls stößt es auf eine, infinite loopwenn der Benutzer ständig falsche Eingaben macht, und wird daher nicht beendet. Gern geschehen. :)
Rohit Jain
Vielen Dank dafür - es hat mich nur davor bewahrt, einen sehr knorrigen Code schreiben zu müssen!
David Holiday
2
Ist es möglich, hier die Funktion Thread.sleep () innerhalb des Catch hinzuzufügen? Denn in einigen Fällen wie das Warten auf Seitenantworten in der Selenium-Bibliothek wurde das kritisch. Vielen Dank.
Suat Atan PhD
2
Funktioniert super! Für Anfänger: Wenn Sie eine positive Endlosschleife erhalten, überprüfen Sie, ob Sie "break" hinzugefügt haben. am Ende im "try" -Block.
Krzysztof Walczewski
59

Obligatorische "Unternehmer" -Lösung:

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

Und um anzurufen:

OperationHelper.doWithRetry(5, new Operation() {
    @Override public void doIt() {
        //do some stuff
    }
    @Override public void handleException(Exception cause) {
        //recover from the Exception
    }
});
ach
quelle
6
Sie sollten die Ausnahme erneut auslösen, wenn der letzte erneute Versuch fehlschlägt, wie in den anderen Antworten angegeben.
Cvacca
35

Wie immer hängt das beste Design von den jeweiligen Umständen ab. Normalerweise schreibe ich aber so etwas wie:

for (int retries = 0;; retries++) {
    try {
        return doSomething();
    } catch (SomeException e) {
        if (retries < 6) {
            continue;
        } else {
            throw e;
        }
    }
}
Meriton
quelle
Warten Sie, warum nicht die Bedingung in der for-Schleifendeklaration wie folgt haben: for (int retries = 0; retries <6; retries ++) ??
Didier A.
8
Weil ich nur den letzten Versuch einwerfen möchte und daher der catch-Block diese Bedingung benötigt, wodurch die Bedingung in der für redundant wird.
Meriton
1
Ich denke nicht, dass continuedas dort gebraucht wird. Und Sie können einfach die if-Bedingung umdrehen.
Koray Tugay
19

Obwohl try/catchin whileist eine bekannte und gute Strategie, möchte ich Ihnen einen rekursiven Aufruf vorschlagen:

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
quelle
41
Wie ist Rekursion für diesen Anwendungsfall besser als eine Schleife?
Dan
7
Der Stack-Trace sieht in diesem limitFall vielleicht etwas seltsam aus, denn hätte er nicht die Anzahl der rekursiven Methoden? Im Gegensatz zur Loop-Version, die auf das "ursprüngliche" Niveau wirft ...
Clockwork-Muse
7
Sicher sieht auf dem Papier elegant aus, aber ich bin mir nicht sicher, ob Rekursion irgendwie der richtige Ansatz ist.
Thomas
3
Ich verstehe nicht, warum Rekursion auch hier. Wie auch immer, ich denke, es könnte vereinfacht werden, um:void retry(int times) { (...) if (times==0) throw w; retry(times--);
sinuhepop
8
Es ist eine schlechte Praxis, die Rekursion als Ersatz für die bloße Iteration zu verwenden. Die Rekursion wird verwendet, wenn Sie Daten pushen und einfügen möchten.
Marquis von Lorne
19

Ihr genaues Szenario, das über Failsafe behandelt wird :

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

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

Ziemlich einfach.

Jonathan
quelle
5
sehr schöne Bibliothek.
Maksim
Für diejenigen, die sich fragen, benötigen Sie dies in Ihren Gradle-Abhängigkeiten - kompilieren Sie 'net.jodah: fehlersicher: 1.1.0'
Shreyas
18

Sie können AOP- und Java-Annotationen unter jcabi-Aspekten verwenden (ich bin Entwickler):

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

Sie können auch @Loggableund @LogExceptionAnmerkungen verwenden.

yegor256
quelle
Wow ! Klingt schick! :)
Alind Billore
Sollte die beste Antwort sein.
Mohamed Taher Alrefaie
2
Gibt es eine Möglichkeit, den Fehler zu "beheben", wenn der Versuch fehlschlägt (führen Sie einige Adoptionen durch, die den nächsten Versuch beheben können)? siehe Frage: fix_the_problem();im
Fangblock
Angesichts der Anzahl offener Probleme und der Zeit, die vergangen ist, damit bestätigte Fehler nicht behoben wurden, würde ich mich nicht auf diese Bibliothek verlassen.
Michael Lihs
6

Die meisten dieser Antworten sind im Wesentlichen gleich. Meins ist es auch, aber das ist die Form, die ich mag

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.
quelle
Ein Nachteil ist, dass Sie auch fix_the_problemnach dem letzten Versuch anrufen . Das könnte eine kostspielige Operation sein und einige Zeit verschwenden.
Joachim Sauer
2
@ JoachimSauer Stimmt. Sie könnten if (tryCount < max) fix()- aber dies ist das Format eines allgemeinen Ansatzes; Die Details würden von einem bestimmten Fall abhängen. Es gibt auch einen Guaven-basierten Retryer, den ich mir angesehen habe.
Stephen P
4

Spring AOP- und annotationsbasierte Lösung:

Verwendung ( @RetryOperationist unsere benutzerdefinierte Anmerkung für den Job):

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

Dazu benötigen wir zwei Dinge: 1. eine Anmerkungsschnittstelle und 2. einen Federaspekt. Hier ist eine Möglichkeit, diese zu implementieren:

Die Anmerkungsschnittstelle:

import java.lang.annotation.*;

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

Der Frühlingsaspekt:

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

Verwenden Sie eine whileSchleife mit lokalem statusFlag. Initialisieren Sie das Flag als falseund setzen Sie es auf, truewenn der Vorgang erfolgreich ist, z. B. unten:

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

Dies wird so lange wiederholt, bis es erfolgreich ist.

Wenn Sie nur eine bestimmte Anzahl von Malen wiederholen möchten, verwenden Sie auch einen Zähler:

  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
  }

Dies wird maximal 10 Mal versucht, wenn es bis dahin nicht erfolgreich ist, und wird beendet, wenn es vorher erfolgreich ist.

Yogendra Singh
quelle
Anstatt nach !successIhrer Zeit zu suchen, können Sie einfach ausbrechen, wenn der Erfolg wahr ist.
Rohit Jain
1
@RohitJain: Es sieht für mich sauberer aus.
Yogendra Singh
@ YogendraSingh .. Seltsam. da Sie Ihre successnirgendwo in Ihrem ändern catch. Es scheint also überflüssig, bei jedem Durchlauf danach zu suchen catch.
Rohit Jain
@RohitJain: Catch korrigiert nur die Daten. Es wird zurückgehen und die Anweisung erneut ausführen. Bei Erfolg wird das geändert success. Versuch es.
Yogendra Singh
3

Dies ist eine alte Frage, aber eine Lösung ist immer noch relevant. Hier ist meine generische Lösung in Java 8 ohne Verwendung einer Bibliothek eines Drittanbieters:

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

Lassen Sie uns einen Testfall haben wie:

@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
quelle
nette Idee, ein Baumeister dafür!
HankTheTank
2

Eine einfache Möglichkeit, das Problem zu lösen, besteht darin, den Versuch / Fang in eine while-Schleife zu packen und eine Zählung aufrechtzuerhalten. Auf diese Weise können Sie eine Endlosschleife verhindern, indem Sie eine Anzahl mit einer anderen Variablen vergleichen und gleichzeitig ein Protokoll Ihrer Fehler führen. Es ist nicht die exquisiteste Lösung, aber es würde funktionieren.

Jordan Kaye
quelle
1

Verwenden Sie ein Do-While, um einen Wiederholungsblock zu entwerfen.

boolean successful = false;
int maxTries = 3;
do{
  try {
    something();
    success = true;
  } catch(Me ifUCan) {
    maxTries--;
  }
} while (!successful || maxTries > 0)
Rahul Malhotra
quelle
2
Der Code sollte die ursprüngliche Ausnahme
auslösen,
1

Für den Fall, dass es nützlich ist, sind ein paar weitere Optionen in Betracht zu ziehen, die alle zusammengewürfelt sind (stopfile statt Wiederholungsversuche, Schlaf, größere Schleife fortsetzen).

 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
quelle
Nach unten Wähler hinterlassen bitte Kommentare, warum, danke!
Rogerdpack
1
Dies ist eine bloße Unwissenheit, abzustimmen und keinen Grund zu nennen.
Xploreraj
Dort zu schlafen ist nicht offensichtlich, da die while-Schleife nicht warten würde
João Pimentel Ferreira
1

Sie können https://github.com/bnsd55/RetryCatch verwenden

Beispiel:

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

Stattdessen new ExampleRunnable()können Sie Ihre eigene anonyme Funktion übergeben.

bnsd55
quelle
1

Wenn nicht alle Ausnahmen einen erneuten Versuch rechtfertigen, nur einige. Und wenn mindestens ein Versuch unternommen werden muss, ist hier eine alternative Dienstprogrammmethode:

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

Verwendung:

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

Alles, was ein Try-Catch bewirkt, ist, dass Ihr Programm ordnungsgemäß fehlschlägt. In einer catch-Anweisung versuchen Sie im Allgemeinen, den Fehler zu protokollieren und gegebenenfalls Änderungen rückgängig zu machen.

bool finished = false;

while(finished == false)
{
    try
    {
        //your code here
        finished = true
    }
    catch(exception ex)
    {
        log.error("there was an error, ex");
    }
}
Sam, ich bin, sagt Reinstate Monica
quelle
meinst du im gegensatz zu (!finished)?
Sam, ich bin, sagt Reinstate Monica
1
@RohitJain es sieht zu sehr nach while(finished). Ich bevorzuge die ausführlichere Version.
Sam, ich bin, sagt Reinstate Monica
3
Wie um alles in der Welt sieht es while(!finished)aus while (finished)?
Rohit Jain
@Rohit Weil es nur ein Zeichen anders ist. Sie werden alle auf dasselbe kompiliert. In C # verwende ich eine String-Erweiterungsmethode, IsPopulated()die nur zurückgibt, !IsNullOrEmpty()um sicherzustellen, dass meine Absicht von allen Entwicklern verstanden wird.
Michael Blackburn
0

Ich weiß, dass es hier bereits viele ähnliche Antworten gibt, und meine ist nicht viel anders, aber ich werde sie trotzdem veröffentlichen, weil sie sich mit einem bestimmten Fall / Problem befasst.

Wenn Sie sich mit dem facebook Graph APIIn beschäftigen, erhalten PHPSie manchmal einen Fehler, aber wenn Sie das Gleiche sofort erneut versuchen, erhalten Sie ein positives Ergebnis (aus verschiedenen magischen Internetgründen, die über den Rahmen dieser Frage hinausgehen). In diesem Fall muss das Problem nicht behoben werden keinen Fehler , sondern es einfach erneut versuchen, da ein "Facebook-Fehler" aufgetreten ist.

Dieser Code wird unmittelbar nach dem Erstellen einer Facebook-Sitzung verwendet:

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

Wenn die forSchleife auf Null ( $attempt--) heruntergezählt wird, ist es außerdem ziemlich einfach, die Anzahl der Versuche in der Zukunft zu ändern.

KnightHawk
quelle
0

Das Folgende ist meine Lösung mit einem sehr einfachen Ansatz!

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

                    }
                }
David Kayo
quelle
1
Bitte schauen Sie sich die Antwort von @Rohit Jain an, die spezifischer ist und in negativen Fällen keine Endlosschleife darstellt.
Chandra Shekhar
0

Ich bin mir nicht sicher, ob dies der "professionelle" Weg ist, und ich bin mir nicht ganz sicher, ob es für alles funktioniert.

boolean gotError = false;

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

Hier ein wiederverwendbarer und allgemeinerer Ansatz für Java 8+, für den keine externen Bibliotheken erforderlich sind:

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

Verwendung:

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

Das Problem bei den verbleibenden Lösungen ist, dass die Korrespondenzfunktion kontinuierlich ohne ein Zeitintervall dazwischen versucht, wodurch der Stapel überflutet wird.

Warum nicht einfach tryjede Sekunde und ad eternum ?

Hier eine Lösung mit setTimeoutund eine rekursive Funktion:

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

Ersetzen Sie die Funktion Run()durch die Funktion oder den Code, die Sie tryjede Sekunde neu erstellen möchten .

João Pimentel Ferreira
quelle
0

Probieren Sie es mit der Annotation springs @Retryable aus. Die folgende Methode versucht es erneut, wenn RuntimeException auftritt

@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
quelle
0

Führen Sie unter dem Snippet ein Code-Snippet aus. Wenn beim Ausführen des Code-Snippets ein Fehler aufgetreten ist, warten Sie M Millisekunden und versuchen Sie es erneut. Referenz Link .

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

Hier ist meine Lösung, ähnlich wie einige andere, die eine Funktion umschließen kann, aber es Ihnen ermöglicht, den Rückgabewert der Funktionen zu erhalten, wenn dies erfolgreich ist.

    /**
     * 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
quelle