どのように再試行キャッチを実装しますか?


203

try-catchは、例外処理を支援することを目的としています。これは、どういうわけか、システムをより堅牢にするのに役立つことを意味します。予期しないイベントからの回復を試みてください。

実行および命令(メッセージの送信)の際に何かが発生する可能性があるため、tryに含まれています。ほぼ予期しないことが発生した場合は、何かを行うことができます。例外をログに記録するためだけに呼び出されたとは思わない。キャッチブロックは、エラーから回復する機会を提供することを目的としています。

ここで、問題点を修正できるため、エラーから回復するとします。再試行するのはとても良いことです:

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

これはすぐに永遠のループに入りますが、fix_the_problemがtrueを返したとしたら、再試行します。Javaにはそのようなことはないので、この問題をどのように解決しますか?これを解決するための最良の設計コードは何ですか?

これは哲学的な質問のようなものです。私が求めていることがJavaで直接サポートされていないことがすでにわかっているからです。


5
それはどのような例外ですか?
Bhesh Gurung

23
私はあなたの例外の名前が好きです。;)
Rohit Jain

実際には、そこから回復できる多くの例外はありません。私は私の最初の動機は、実際の例外ではありませんでした認めるが、それはほとんど決して起こらない場合の方法は避けるために:私がしようremove()からjava.util.Queue、thorwsとそのInvalidElementExceptionキューが空の場合。空であるかどうかを尋ねるのではなく、try-catchでアクションをサラウンドします(同時実行では、前のifでも強制的になります)。このような場合、catchブロックで、キューに要素を追加して再試行するように依頼します。出来上がり。
Andres Farias

1
これを行う通常の方法はDBアクセスの場合であることがわかります。接続が再接続に失敗した場合、接続に失敗した場合はメジャー例外をスローし、そうでない場合は呼び出しを再試行します。既に述べたように、一番下にチェックがあるループでそれを行うことができますif(error <> 0)そして戻ってさもなければブレークします;
テレサフォースター

回答:


304

次のようにループtry-catch内に囲む必要がありますwhile:-

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

私が撮影しているcountmaxTries例外があなたで発生し続けている場合には、無限ループに実行しないようにtry block


3
maxTriesなしで、最初はこのようなものを考えました。答えてくれてありがとう!
Andres Farias

6
@AndresFarias ..ええ、この回答で最も重要な点はを含めることmaxTriesです。infinite loopそうでない場合、ユーザーが継続的に間違った入力を行った場合に実行されるため、終了しません。どういたしまして。:)
Rohit Jain

これをありがとう-それは私にいくつかの非常に恐ろしいコードを書かなければならないことから私を救いました!
David Holiday

2
ここのキャッチ内にThread.sleep()関数を追加することは可能ですか?重要になったSeleniumライブラリでページ応答を待つような場合もあるからです。ありがとう。
Suat Atan PhD

2
よく働く!初心者向け:正の無限ループが発生した場合は、「ブレーク」を追加したかどうかを確認します。「try」ブロックの最後。
Krzysztof Walczewski 2017

59

義務的な「エンタープライズ」ソリューション:

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

そして呼び出す:

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

6
与えられた他の回答で行われているように、最後の再試行が失敗した場合は、例外を再スローする必要があります。
cvacca 2014年

35

いつものように、最良の設計は特定の状況に依存します。通常、しかし、私は次のようなものを書きます:

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

待って、なぜforループ宣言の中に次のような条件がないのですか:for(int retries = 0; retries <6; retries ++)??
Didier A.

8
私は最後の試行でのみスローしたいので、catchブロックはその条件を必要とし、の条件を冗長にします。
メリトン2014年

1
continueそこでは必要ないと思います。そして、if条件を単純に反転できます。
Koray Tugay

19

try/catchにはwhileよく知られており、良い戦略されて私はあなたの再帰呼び出しを提案したいです。

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
このユースケースでは、再帰はループよりも優れていますか?
Dan、

7
スタックトレースは、limit再帰されているメソッドの数がないので、これでは少し奇妙に見えるかもしれません。「元の」レベルでスローされるループバージョンとは対照的に...
Clockwork-Muse

7
確かに紙の上ではエレガントに見えますが、どういうわけか再帰が正しいアプローチであるかどうかはわかりません。
トーマス

3
なぜここで再帰するのか分かりません。:とにかく、私はそれが簡単にすることができると思いますvoid retry(int times) { (...) if (times==0) throw w; retry(times--);
sinuhepop

8
単なる反復の代わりに再帰を使用することはお勧めできません。再帰は、一部のデータをプッシュおよびポップするときに使用します。
ローンの侯爵

19

あなたの正確なシナリオは Failsafeで

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

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

ものすごく単純。


5
とても素敵なライブラリ。
マクシム

不思議に思う人のために、gradleの依存関係でこれが必要になります-'net.jodah:failsafe:1.1.0'をコンパイルします
Shreyas

18

jcabi-aspects(私は開発者です)からAOPおよびJavaアノテーションを使用できます。

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

@Loggableおよび@LogExceptionアノテーションを使用することもできます。


うわー !ファンシーですね!:)
Alind Billore 2015

トップアンサーでなければなりません。
Mohamed Taher Alrefaie 2016年

2
試行が失敗したときにエラーを "修正"する方法はありますか(次の試行を修正する可能性があるいくつかの採用はありますか)?質問を参照してください:fix_the_problem();キャッチブロック内
ワーチ

未解決の問題の量と、確認されたバグが修正されないまま時間が経過したことを考えると、このライブラリには依存しません。
Michael Lihs、2018年

6

これらの答えのほとんどは基本的に同じです。私もですが、これは私が好きな形です

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

1つの欠点はfix_the_problem、最後の試行後にも呼び出すことです。これコストのかかる操作であり、時間を浪費する可能性があります。
Joachim Sauer、2013

2
@JoachimSauer真。可能ですがif (tryCount < max) fix()、これは一般的なアプローチの形式です。詳細は特定のケースに依存します。私が見てきたグアバベースのリトライアもあります。
Stephen P

4

Spring AOPおよびアノテーションベースのソリューション:

使用法(@RetryOperationジョブのカスタムアノテーション):

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

これを実現するには、2つのものが必要です。1。アノテーションインターフェイス、2。スプリングアスペクト。これらを実装する1つの方法を次に示します。

注釈インターフェース:

import java.lang.annotation.*;

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

春の側面:

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

whileローカルstatusフラグでループを使用します。フラグを次のように初期化し、操作が成功falseしたtrueときにそれを設定します。

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

これは、成功するまで再試行を続けます。

特定の回数だけ再試行する場合は、カウンターも使用します。

  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
  }

これは、それまで成功しなかった場合、最大10回試行し、それまでに成功した場合は終了します。


!successしばらくの間チェックするのではなく、成功が本当であるときだけ、時間から抜け出すことができます。
Rohit Jain

1
@RohitJain:私にはもっときれいに見えます。
Yogendra Singh

@YogendraSingh ..奇妙です。あなたはあなたのあなたのsuccessどこにもあなたを変更していないのでcatch。したがって、を実行するたびに、それをチェックすることは冗長に思われますcatch
Rohit Jain

@RohitJain:Catchはデータを修正しているだけです。戻ってステートメントを再度実行します。成功すると、が変更されsuccessます。やってみよう。
Yogendra Singh

3

これは古い質問ですが、解決策はまだ適切です。サードパーティのライブラリを使用しないJava 8での私の一般的な解決策を次に示します。

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

次のようなテストケースを作成してみましょう。

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

いいアイデア、あちこちのビルダー!
HankTheTank

2

この問題を解決する簡単な方法は、try / catchをwhileループでラップし、カウントを維持することです。このようにして、失敗のログを維持しながら、他の変数に対してカウントをチェックすることで、無限ループを防ぐことができます。これは最も精巧なソリューションではありませんが、機能します。


1

do-whileを使用して、再試行ブロックを設計します。

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

2
失敗した場合、コードは元の例外をスローする必要があります
lilalinux

1

それが便利な場合は、考慮すべきいくつかの追加オプションがすべて一緒にスローされます(再試行の代わりにストップファイル、スリープ、より大きなループを続ける)すべてがおそらく役立つでしょう。

 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 2016年

1
これは、反対の投票に対するまったくの無知であり、理由を引用するものではありません。
xploreraj 2017

whileループが待っていないであろうから明白でありません眠っている
ジョアン・ピメンテル・フェレイラ

1

https://github.com/bnsd55/RetryCatchを使用できます

例:

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

代わりにnew ExampleRunnable()、独自の無名関数を渡すことができます。


1

すべての例外が再試行を保証するわけではない場合は、一部のみです。そして、少なくとも1つの試行を行う必要がある場合は、代替のユーティリティメソッドを次に示します。

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

使用法:

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

0

Try-Catchが行うことはすべて、プログラムを正常に失敗させることです。catchステートメントでは、通常、エラーをログに記録し、必要に応じて変更をロールバックします。

bool finished = false;

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

とは対照的にどういう意味(!finished)ですか?
サム私はモニカーを復活させる

1
@RohitJainそれはあまりにも似ていwhile(finished)ます。私はより詳細なバージョンを使用することを好みます。
サム私はモニカーを復活させる

3
一体どのようにwhile(!finished)見えますwhile (finished)か?
Rohit Jain

@Rohitは1文字だけ違うので。それらはすべて同じものにコンパイルされます。C#では、すべての開発者が私の意図を確実に理解するためにIsPopulated()戻るだけのString拡張メソッドを使用しています!IsNullOrEmpty()
マイケルブラックバーン

0

ここにはすでに似たような答えがたくさんあることは知っています。私もそれほど大きな違いはありませんが、特定のケース/問題を扱っているのでとにかく投稿します。

facebook Graph APIin PHPを処理するときにエラーが発生することがありますが、すぐに同じことを再試行すると、肯定的な結果が得られます(この質問の範囲を超えるさまざまな魔法のインターネットの理由により)。この場合、修正する必要はありません、エラー何らかの "facebookエラー"が発生したため、単に再試行する必要があります。

このコードは、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(); }
    }
}

また、forループカウントをゼロ($attempt--)に減らすことで、将来の試行回数を簡単に変更できます。


0

以下は非常にシンプルなアプローチによる私の解決策です!

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

                    }
                }

1
@Rohit Jainの回答を参照してください。これは、より具体的で、否定的な場合の無限ループではありません。
Chandra Shekhar

0

これが「プロフェッショナルな」方法であるかどうかはわかりませんが、すべてで機能するかどうかは完全にはわかりません。

boolean gotError = false;

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


0

ここでは、外部ライブラリを必要としない、Java 8以降の再利用可能でより一般的なアプローチを示します。

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

使用法:

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

0

残りのソリューションの問題は、対応する関数が時間間隔を空けずに継続的に試行するため、スタックがオーバーフラッディングすることです。

なぜtry毎秒、そして残りの数だけを使用しないのですか?

ここではsetTimeout、再帰関数を使用したソリューション:

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

1秒ごとにRun()やり直したい関数またはコードで関数を置き換えますtry


0

Springs @Retryableアノテーションを使用して試してみてください、以下のメソッドは、RuntimeExceptionが発生したときに3回試行します

@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

以下のスニペットは、いくつかのコードスニペットを実行します。コードスニペットの実行中にエラーが発生した場合は、Mミリ秒間スリープしてから再試行してください。参照リンク

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

これは、他のいくつかの関数と同じように関数をラップできる私の解決策ですが、成功した場合は関数の戻り値を取得できます。

    /**
     * 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");
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.