それがもはや例外をスローしなくなるまで、C#で関数を繰り返す

SOAPインターフェイスを呼び出すクラスがあり、データの配列を取得します。ただし、この要求がタイムアウトすると、例外がスローされます。これはいい。しかし、私のプログラムがこの呼び出しをやり直そうとしています。タイムアウトした場合は、成功するまでこの呼び出しを続けてください。どうすればこれを達成できますか?

例えば:

try
{
   salesOrdersArray = MagServ.salesOrderList(sessID, filter);
}
catch
{
   ?? What Goes Here to FORCE the above line of code to rerun until it succeeds.
}
7
例外がスローされないようにタイムアウトを増やしますか?
追加された 著者 ChaosPandion,
これらすべての回答のうち、より詳細な例外を検出するよう指示する人はいません。 tryブロックに無効な状態のオブジェクトが含まれていて、 salesOrderList を取得するとどうなりますか?再試行は決して成功しません。
追加された 著者 Marc,
catchブロック( B )からメソッドを再度呼び出すことができます。サービスが長期間停止した場合はどうなりますか?メソッドを再帰的に24時間実行しますか?私はそれを設定された回数のリトライに制限することをお勧めします。
追加された 著者 Tim,

11 答え

永遠にループする必要があります:

while (true)
{
    try
    {
        salesOrdersArray = MagServ.salesOrderList(sessID, filter);
        break;//Exit the loop. Could return from the method, depending
              //on what it does...
    }
    catch
    {
       //Log, I suspect...
    }
}

実際に永遠にループすることはほとんどありません 。ほとんどの場合、試行回数は最大限にとどめておかなければならず、たぶん特定の例外を捕捉するだけです。 salesOrderList (非従来型メソッド名、btw)が ArgumentNullException をスローすると想像してください all バグがあり、 filter がnullのため... 本当に CPUの100%を永久に縛りたいのですか?

16
追加された
@ティム:私は下の段落を追加していた - 基本的にコードは、直接質問に答えるが、段落は、おそらく良い考えではないことを説明します:)
追加された 著者 Jon Skeet,
@psyklopz:catchブロックに例外タイプを指定します: catch(SoapException)など複数の異なる例外タイプを複数のcatchブロックで指定できます。
追加された 著者 Jon Skeet,
私がこのようなことをするとき、適切な持続時間の Sleep を入れて、何らかのサービスがオンラインに戻るのを待っているCPUの100%を使用しないようにします。私は小さなネットワークの不具合から迅速に回復するように制限された指数バックオフ(TCPのような)を含んでいるかもしれませんが、サービスが長期間ダウンしている場合は数分ごとに1回試行します。
追加された 著者 Gabe,
特定の例外に対して+1、私はあなたの編集中に質問に私のコメントを入力していた。
追加された 著者 Marc,
システムリソースを(潜在的に)縛り付けたり、呼び出し元のアプリケーションを応答不能にすることはできませんでしたか?私にとって最高の解決策のようには聞こえません...
追加された 著者 Tim,
あなたはまた、前の時刻を取得してから差分b/wまで待ってから5秒を超えてから抜け出すことができます。
追加された 著者 Mr Universe,
私は知っている、私は特定の例外、SOAPエラーなどをキャッチする休憩の喜びを忘れて、ありがとう。
追加された 著者 psyklopz,

タイムアウトを変更できない場合、以下が有効になります。 salesOrdersArrayは null に初期化する必要があります。

while(salesOrdersArray == null)
{
    try
    {
       salesOrdersArray = MagServ.salesOrderList(sessID, filter);
    }
    catch
    {
      //Log failure
    }
}
4
追加された
+1:私はこれがJonの答えよりも少し好きです。私はそれがループの最終状態をより明白にすると思う。
追加された 著者 Brian,

それは、コントロールフローとして例外を使用することは、一般的には理想的ではありませんが、これはあなたが要求したことを行います。

bool Caught = true;
while (Caught)
try
{
    salesOrdersArray = MagServ.salesOrderList(sessID, filter);
    Caught = false;
}
catch
{
    Caught = true;
}
1
追加された

トランザクションキュー(MSMQ)を使用してサービスコールを保存します。ループによってメッセージがデキューされ、TransactionScopeでサービスがコールされます。コールが失敗した場合、メッセージはキューに残っているように見えます。 ov erall timeoutは、メッセージに期限が切れる時刻を追加することで指定できます。その操作を呼び出すことが重要であると推測して以来、本当に信頼できるソリューションが必要な場合、このソリューションは良いことです。

1
追加された

ループ構造内にtry/catchブロックを配置する必要があります。あなたのプロセッサーの100%を消費したくない場合は、catchブロックにThread.Sleepを置きます。例外が発生するたびに、それはしばらく待ってプロセッサーが他のことをするのを解放します。

// iterate 100 times... not forever!
for (int i = 0; i < 100; i++)
{
    try {
       //do your work here;

        break;//break the loop if everything is fine
    } catch {
        Thread.Sleep(1000);
    }
}

また、タイムアウト例外だけが処理されるように例外タイプを指定し、その他の種類のパススルーを指定することもできます。

// iterate 100 times... not forever!
for (int i = 0; i < 100; i++)
{
    try {
       //do your work here;

        break;//break the loop if everything is fine
    } catch (TimeOutException) {
        Thread.Sleep(1000);
    }
}

TimeOutExceptionは例外の実名に置き換えられるべきであることに注意してください...それが本当の名前かどうかわかりません。

私が提示したケースでは、1000ミリ秒の100回のリピートで1分40秒の最長待機時間と操作時間自体を加えた、睡眠時間をミリ秒とリピート量で調整します。

1
追加された

試す

bool failed = false;
do {
 試す
 {
  salesOrdersArray = MagServ.salesOrderList(sessID, filter);
 }
 catch
 {
  failed = true;
 }
} while(failed);

これは決して成功しない場合は、あなたが後の動作は無限ループを引き起こす可能性があります...

0
追加された

無限の回数だけこれを行うことはお勧めしませんが、その1つの文から別の関数を作ることができます:

void GoConnect()
{
    try
    {
        salesOrdersArray = MagServ.salesOrderList(sessID, filter);
    }
    catch
    {
        GoConnect();
    }
}
0
追加された
bool repeat = true;
while (repeat)
{
    try
    {
       salesOrdersArray = MagServ.salesOrderList(sessID, filter);
       repeat = false;
    }
    catch
    {
    }
}
0
追加された

私はこの問題を解決するためにこのパターンに従います:

    public void Send(String data, Int32 attemptNumber)
    {
        try
        {
            yourCodeHere(data);
        }
        catch (WebException ex)
        {
            if (attemptNumber > 0)
                Send(data, --attemptNumber);
            else
                throw new AttemptNumberExceededException("Attempt number exceeded!", ex);
        }
        catch (Exception ex)
        {
            //Log pourpose code goes here!
            throw;
        }
    }

あなたが無限のプロセスを持つことになるかもしれないので、永遠に試してみることは良い考えではないようです。あなたの目標を達成するために多くの試みが必要だと思うなら、ここで膨大な数を設定してください。

callig Send(data); の前に、 Thread.Sleep(1000); のように、数ミリ秒、あなたのシナリオに賢明だと思うなら、attempNumber変数を使用してこの待ち時間を増減してください。

0
追加された
なぜ私はいけませんか?私の主張は、彼が書いたコードの下のJon Skeetと同じです
追加された 著者 Renato Gama,
ありがとう@asawyerはそれについて知らなかったので私は私の答えを編集しました!今は大丈夫ですか?
追加された 著者 Renato Gama,
それは本当の意味がある...!このように思ったことはありません...あなたを退屈させて申し訳ありません、今はどうですか?
追加された 著者 Renato Gama,
throw ex; しないでください!
追加された 著者 asawyer,
追加された 著者 asawyer,
2つのこと:1基本例外クラスをキャッチすることはほとんどありません。そうした場合は、ロギング目的のためだけであり、 throw を再度実行します。 2 - ベースの Exception クラスは投げないでください。あなたはコードを消費して Exception を捕まえるという悪い習慣を強いられています。より適切なサブクラスを使用するか、独自のサブクラスを作成します。
追加された 著者 asawyer,
ベストプラクティスを読むにはちょっと時間をかけてください。すぐにビジネスに取り掛かることができます。いくつかの良いリンクがあります: blogs.msdn。 com/b/ericlippert/archive/2008/09/10 /&hellip; codeproject.com/KB/architecture/exceptionbestpractices.aspx
追加された 著者 asawyer,
ああ、それは編集を意味します。いいね! :)
追加された 著者 asawyer,

次のようなことを試してください:

var failed = true;
while (failed)
{
  try 
  {
    salesOrdersArray = MagServ.salesOrderList(sessID, filter); 
    failed = false;
  }
  catch
  {
  }
}

編集:うわー!偉大な心は似ていると思う! :)

0
追加された
while(salesOrdersArray == null){

  try
  {
    salesOrdersArray = MagServ.salesOrderList(sessID, filter);
  }
  catch(salesOrderException e)
  {
     log(e.message);
  }
}

これは永遠に実行され、遅いループとして例外を使用しています。例外をスローするのではなく、nullを返す関数を変更する方法はありますか?この呼び出しが定期的に失敗することが予想される場合は、try/catchブロックを使用しないでください。

0
追加された