Yeniden yakalamayı nasıl uygularsınız?


203

Try-catch, istisna yönetiminde yardımcı olmayı amaçlar. Bu, bir şekilde sistemimizin daha sağlam olmasına yardımcı olacağı anlamına gelir: beklenmedik bir olaydan kurtarmaya çalışın.

Yürütme ve talimat verirken (mesaj gönderirken) bir şey olabileceğinden şüpheleniyoruz, bu yüzden denemeye dahil oluyor. Bu neredeyse beklenmedik bir şey olursa, bir şey yapabiliriz: yakalamayı yazıyoruz. Sadece istisnayı günlüğe kaydetmeye çağırdığımızı sanmıyorum. Yakalama bloğunun bize hatadan kurtulma fırsatı vermek için bir şey olduğunu düşünüyorum.

Şimdi diyelim ki hatadan kurtulduk çünkü yanlış olanı düzeltebiliriz. Yeniden denemek çok güzel olabilir:

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

Bu hızla sonsuz döngüye girer, ancak diyelim ki fix_the_problem doğru döner, sonra tekrar deneriz. Java'da böyle bir şey olmadığı göz önüne alındığında, bu sorunu nasıl çözersiniz? Bunu çözmek için en iyi tasarım kodunuz nedir?

Ne istediğimi zaten bildiğim için bu felsefi bir soru gibidir, Java tarafından doğrudan desteklenmemektedir.


5
Bu nasıl bir istisna?
Bhesh Gurung

23
Yine de istisnanın adını seviyorum. ;)
Rohit Jain

Tapuda, kurtarabileceğiniz pek bir istisna yoktur. İlk motivasyonumun gerçek bir istisna olmadığını itiraf ediyorum, ama bu neredeyse hiç olmayacaksa, bundan kaçınmanın yolu: remove()Bir java.util.Queuethorws ve InvalidElementExceptionkuyruk boş olduğunda deniyorum . Boş olup olmadığını sormak yerine, bir try-catch içindeki eylemleri ekliyorum (eşzamanlılık altında bir önceki if ile bile zorunlu hale gelir). Böyle bir durumda, catchblokta kuyruğu daha fazla elemanla doldurmayı ve sonra tekrar denemeyi isterdim. Voila.
Andres Farias

1
Bağlantı yeniden bağlanma başarısız olursa, o zaman büyük bir istisna atmak aksi takdirde çağrıyı yeniden deneyin, bağlantı yapmak yeniden bağlanırsa DB erişim için olacağını olağan bir şekilde görebilirsiniz. Daha önce de söylendiği gibi, altta bir kontrolle (hata <> 0) bir döngü halinde yapabiliriz, aksi takdirde geri dönün;
Theresa Forster

Yanıtlar:


306

Bunun gibi try-catchbir whiledöngüyü içine almanız gerekir : -

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

Ben almış countve maxTriesistisna Gözlerinde farklı meydana devam ediyor durumda kaçınmak için, sonsuz bir döngüye çalışan try block.


3
İlk başta böyle bir şeyi düşündüm, maxTries olmadan. Cevap için teşekkürler!
Andres Farias

6
@AndresFarias .. Evet, bu cevabın en önemli noktası a maxTries. Aksi infinite looptakdirde, kullanıcı sürekli olarak yanlış girdi verirse ve bu nedenle çıkmayacaksa çalışır. Yine de hoş geldiniz. :)
Rohit Jain

Bunun için teşekkür ederim - sadece çok korkunç bir kod yazmak zorunda kalmadı!
David Holiday

2
Burada yakalamak içine Thread.sleep () işlevi eklemek mümkün mü? Çünkü bazı durumlarda Selenyum kütüphanesinde sayfa yanıtı beklemek gibi kritik hale geldi. Teşekkürler.
Suat Atan Doktora

2
Harika çalışıyor! Yeni başlayanlar için: Pozitif sonsuz döngü elde ederseniz, "break;" sonunda "try" bloğunda.
Krzysztof Walczewski

59

Zorunlu "girişimcilik" çözümü:

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

Ve aramak için:

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

6
Verilen diğer cevaplarda olduğu gibi, son yeniden deneme başarısız olursa istisnayı yeniden atmanız gerekir.
cvacca

35

Her zamanki gibi, en iyi tasarım belirli koşullara bağlıdır. Genellikle olsa, ben gibi bir şey yazmak:

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

Bekleyin, neden for döngüsü bildirimi içinde şu duruma sahip değilsiniz: for (int retries = 0; retries <6; retries ++) ??
Didier A.

8
Çünkü sadece son denemeyi atmak istiyorum ve bu nedenle catch bloğunun bu koşula ihtiyacı var, koşulu gereksiz kılıyor.
meriton

2
Bunun continuegerekli olduğunu düşünmüyorum .. Ve eğer if koşulunu çevirebilirsiniz.
Koray Tugay

19

Her ne kadar iyi bilinen ve iyi bir strateji olsa try/catchda whilesize tekrarlı çağrı önermek istiyorum:

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
Özyineleme bu kullanım durumu için bir döngüden nasıl daha iyidir?
Dan

7
Yığın izlemesi bu konuda biraz garip görünebilir, çünkü limityinelenen yöntemin sayısı olmaz mı? 'Orijinal' düzeyde atacak döngü sürümünün aksine ...
Clockwork-Muse

7
Tabii kağıt üzerinde zarif görünüyor ama yinelemenin bir şekilde doğru yaklaşım olduğundan emin değilim.
Thomas

3
Burada da özyineleme neden anlamıyorum. Her neyse, bunun basitleştirilebileceğini düşünüyorum:void retry(int times) { (...) if (times==0) throw w; retry(times--);
sinuhepop

8
Özyinelemeyi yalnızca yinelemenin yerine kullanmak zayıf bir uygulamadır. Özyineleme, bazı verileri itmek ve patlatmak istediğinizde kullanım içindir.
Lorne Marquis

19

Failsafe aracılığıyla ele alınan tam senaryo :

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

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

Gayet basit.


5
çok güzel bir kütüphane.
Maksim

merak edenler için, buna bağımlı bağımlılıklarınızda ihtiyacınız olacak - 'net.jodah: failsafe: 1.1.0' derleyin
Shreyas

18

AOP ve Java ek açıklamalarını jcabi yönlerinden kullanabilirsiniz (ben bir geliştiriciyim):

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

Ayrıca kullanabilirsiniz @Loggableve @LogExceptionek açıklamalar.


Vaov ! Fantezi geliyor! :)
Alind Billore

En iyi cevap olmalı.
Mohamed Taher Alrefaie

2
girişim başarısız olduğunda "düzeltmek" için bir yol var mı (bir sonraki girişimi düzeltebilecek bazı kabuller yapmak)? soruya bakın: fix_the_problem();catch bloğunda
warn

Açık sorunların miktarı ve kabul edilen hataların düzeltilmemesi için geçen süre göz önüne alındığında, bu kütüphaneye güvenmem.
Michael Lihs

6

Bu cevapların çoğu aslında aynıdır. Benimki de, ama bu benim sevdiğim form

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

Tek dezavantajı, fix_the_problemson denemeden sonra da arama yapmanızdır . Yani olabilir pahalı bir operasyon ve biraz zaman israf olabilir.
Joachim Sauer

2
@JoachimSauer Doğru. Yapabilirsiniz if (tryCount < max) fix()- ama bu genel bir yaklaşımın biçimidir; ayrıntılar belirli bir duruma bağlı olacaktır. Ayrıca baktığım bir guava tabanlı Retryer var .
Stephen P

4

Bahar AOP ve ek açıklama tabanlı çözüm:

Kullanım ( @RetryOperationbizim iş için özel not):

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

Bunu başarmak için iki şeye ihtiyacımız olacak: 1. bir ek açıklama arayüzü ve 2. bir bahar yönü. Bunları uygulamanın bir yolu:

Ek Açıklama Arayüzü:

import java.lang.annotation.*;

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

Bahar Boyutu:

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

whileYerel statusbayraklı bir döngü kullanın . Bayrağı şu şekilde başlatın ve işlem başarılı olduğunda şu şekilde falseayarlayın true: örneğin:

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

Bu, başarılı olana kadar yeniden denemeye devam edecektir.

Sadece belirli sayıda tekrar denemek istiyorsanız bir sayaç da kullanın:

  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
  }

Bu, o zamana kadar başarılı olmazsa en fazla 10 kez deneyecektir.


!successSüre içinde kontrol etmek yerine , başarının doğru olduğu zamandan çıkabilirsiniz.
Rohit Jain

1
@RohitJain: Benim için daha temiz görünüyor.
Yogendra Singh

@YogendraSingh .. Garip. çünkü successiçinde hiçbir yerde değişiklik yapmıyorsunuz catch. Bu yüzden, her koşusunda kontrol etmek gereksiz görünüyor catch.
Rohit Jain

@RohitJain: Catch sadece verileri düzeltiyor. Geri dönecek ve ifadeyi tekrar çalıştıracak. Başarılı olursa success,. Denemek.
Yogendra Singh

3

Bu eski bir soru ama bir çözüm hala geçerli. İşte herhangi bir üçüncü taraf kitaplığı kullanmadan Java 8'deki genel çözümüm:

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

Gibi bir test vakası yapalım:

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

güzel fikir, bunun için bir inşaatçı!
HankTheTank

2

Sorunu çözmenin basit bir yolu, try / catch'i bir while döngüsüne sarmak ve bir sayıyı korumaktır. Bu şekilde, hatalarınızın bir kaydını tutarken diğer bazı değişkenlere karşı bir sayıyı kontrol ederek sonsuz bir döngüyü önleyebilirsiniz. En zarif çözüm değil, ama işe yarayacaktı.


1

Yeniden deneme bloğu tasarlamak için bir süre kullanın.

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

2
Başarısız olursa kod orijinal istisnayı
atmalıdır

1

Yararlı olması durumunda, hepsi birlikte atılacak birkaç seçenek daha (yeniden deneme yerine uyku dosyası, uyku, daha büyük döngüye devam) muhtemelen yararlı.

 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
}

Aşağı seçmenler lütfen neden olduğu hakkında yorum bırakın, teşekkürler!
rogerdpack

1
Bu, aşağı inmek ve bir neden belirtmek için ciddi bir cehalettir.
xploreraj

while döngüsü beklemez beri orada belli değil uyku
João Pimentel Ferreira

1

Https://github.com/bnsd55/RetryCatch kullanabilirsiniz

Misal:

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

Bunun yerine new ExampleRunnable()kendi anonim işlevinizi iletebilirsiniz.


1

Tüm istisnalar yeniden denemeyi gerektirmiyorsa, sadece bazıları. Ve en az bir deneme yapılması gerekiyorsa, İşte alternatif bir yardımcı yöntem:

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

Kullanımı:

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

0

Try-Catch'in yaptığı tek şey programınızın zarif bir şekilde başarısız olmasına izin vermektir. Bir catch deyiminde, genellikle hatayı günlüğe kaydetmeye çalışırsınız ve gerekirse değişiklikleri geri alabilirsiniz.

bool finished = false;

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

aksine değil (!finished)mi demek istiyorsun ?
Sam, Reinstate Monica

1
@RohitJain çok benziyor while(finished). Daha ayrıntılı sürümü kullanmayı tercih ederim.
Sam, Reinstate Monica

3
Dünyada nasıl while(!finished)görünüyor while (finished)?
Rohit Jain

@Rohit Çünkü bu sadece bir karakter farklı. Hepsi aynı şeye derlenir. C #, ben IsPopulated()sadece !IsNullOrEmpty()niyetimin tüm geliştiriciler tarafından anlaşıldığından emin olmak için döndüren bir String uzantısı yöntemi kullanın .
Michael Blackburn

0

Burada zaten birçok benzer cevap olduğunu biliyorum ve benimki çok farklı değil, ama yine de göndereceğim çünkü belirli bir vaka / sorunla ilgileniyor.

İle uğraşırken facebook Graph APIiçinde PHPsize bazen hata olsun, ama hemen yeniden çalışıyor (çeşitli için olumlu bir sonuç verecektir aynı şeyi büyülü Bu sorunun kapsamı dışında internet nedenlerle). Bu durumda, düzeltmeye gerek yoktur herhangi bir hatayı , ancak bir tür "facebook hatası" olduğu için tekrar denemek yeterlidir.

Bu kod bir facebook oturumu oluşturduktan hemen sonra kullanılır:

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

Ayrıca, fordöngünün sıfıra ( $attempt--) geri sayılması , gelecekteki deneme sayısını değiştirmeyi oldukça kolaylaştırır.


0

takip benim çözüm çok basit bir yaklaşım ile!

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

                    }
                }

1
lütfen negatif durumlarda sonsuz bir döngü değil daha spesifik olan @Rohit Jain cevabına bakın.
Chandra Shekhar

0

Im bunu yapmak için "Profesyonel" yolu olup olmadığından emin değilim ve ben her şey için çalışır tamamen emin değilim.

boolean gotError = false;

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


0

Harici kütüphaneler gerektirmeyen Java 8+ için yeniden kullanılabilir ve daha genel bir yaklaşım:

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

Kullanımı:

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

0

Geri kalan çözümlerle ilgili sorun, muhabir fonksiyonun aradaki bir zaman aralığı olmadan sürekli olarak çalışması, böylece yığını fazla doldurmasıdır.

Neden trysadece her saniyede ve ad eternumda değil ?

Burada bir çözüm setTimeoutve özyinelemeli bir işlev:

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

İşlevi Run(), tryher saniye yeniden oluşturmak istediğiniz işlev veya kodla değiştirin .


0

@Retryable ek açıklamalarını kullanmayı deneyin, RuntimeException oluştuğunda aşağıdaki yöntem 3 deneme için yeniden dener

@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

Snippet'in altında bazı kod snippet'lerini yürütün. Kod snippet'ini yürütürken herhangi bir hatayla karşılaşırsanız, M milisaniye bekleyin ve tekrar deneyin. Referans bağlantısı .

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

İşte benim çözüm başkalarına benzer bir işlevi sarabilir, ama eğer işe yarıyorsa, işlevlerin dönüş değerini almanızı sağlar.

    /**
     * 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");
    }
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.