3

以下は、例外がキャッチされている間に何かを再実行するロジックをカプセル化しようとするコードです。

それを行うためのパターンまたは何か他のものが存在しますか? または、そのコードにどのような改善を提案しますか?

    public static void DoWhileFailing(int triesAmount, int pauseAmongTries, Action codeToTryRun) {
        bool passed = false;
        Exception lastException = null;

        for (int i = 0; !passed && i < triesAmount; i++) {
            try {
                if (i > 0) {
                    Thread.Sleep(pauseAmongTries);
                }
                codeToTryRun();
                passed = true;
            } catch(Exception e) {
                lastException = e;
            }
        }

        if (!passed && lastException != null) {
            throw new Exception(String.Format("Something failed more than {0} times. That is the last exception catched.", triesAmount), lastException);
        }
    }
4

3 に答える 3

3

いくつかの変数を削除するためにこれを書き直しますが、一般的にあなたのコードは問題ありません:

public static void DoWhileFailing(int triesAmount, int pauseAmongTries, Action codeToTryRun) {
    if (triesAmount<= 0) {
        throw new ArgumentException("triesAmount");
    }
    Exception ex = null;
    for (int i = 0; i < triesAmount; i++) {
        try {
            codeToTryRun();
            return;
        } catch(Exception e) {
            ex = e;
        }
        Thread.Sleep(pauseAmongTries);
    }
    throw new Exception(String.Format("Something failed more than {0} times. That is the last exception catched.", triesAmount, ex);
}
于 2012-12-20T15:53:25.760 に答える
1

基本的に同じことを行うために、次のコードを書きました。また、キャッチする例外のタイプとFunc、現在の反復で例外をスローするか、再試行を続行するかを決定することもできます。

public static void RetryBeforeThrow<T>(
    this Action action, 
    Func<T, int, bool> shouldThrow, 
    int waitTime) where T : Exception
{
    if (action == null)
        throw new ArgumentNullException("action");
    if (shouldThrow == null)
        throw new ArgumentNullException("shouldThrow");
    if (waitTime <= 0)
        throw new ArgumentException("Should be greater than zero.", "waitTime");
    int tries = 0;
    do
    {
        try
        {
            action();
            return;
        }
        catch (T ex)
        {
            if (shouldThrow(ex, ++tries))
                throw;
            Thread.Sleep(waitTime);
        }
    }
    while (true);
}

次に、このように呼び出すことができます

Action a = () => 
    { 
        //do stuff 
    };
a.RetryBeforeThrow<Exception>((e, i) => i >= 5, 1000);

また、任意の例外タイプを指定でき、 で例外をチェックして、Funcスローする例外か、再試行を続けるかを判断できます。Actionこれにより、再試行の発生を停止する独自の例外をスローすることができます。

于 2012-12-20T16:02:03.723 に答える
1

コードに問題はありません。あなたの仮定に疑問を投げかけるだけです。

私が見るいくつかの問題:

  • クライアントは、適切なパラメーターを選択するために、呼び出されたアクションの失敗モードを理解する必要があります。
  • アクションは断続的に失敗する可能性があり、これはキャパシティ キラーです。このようなコードはうまくスケーリングできません。
  • クライアントは、アクションが完了するまで不確定な時間待機できます。
  • 最後の例外を除くすべての例外が飲み込まれ、重要な診断情報が隠される可能性があります。

ニーズによっては、コードで十分かもしれませんが、信頼性の低いリソースをカプセル化するためのより堅牢な方法については、サーキット ブレーカーパターンをご覧ください。

于 2012-12-20T16:24:59.447 に答える