2009-06-26 110 views
0

我在我的web應用程序上使用xml web服務,有時遠程服務器無法及時響應。如果第一次嘗試失敗,我想出了重新請求的想法。爲了防止循環,我想限制在2的併發請求。我想得到一個意見,如果我在下面做了什麼是可以的,並會按我的預期工作。如果第一個失敗,請重試請求

public class ScEngine 
{ 
    private int _attemptcount = 0; 
    public int attemptcount 
    { 
     get 
     { 
      return _attemptcount; 
     } 
     set 
     { 
      _attemptcount = value; 
     } 
    } 

    public DataSet GetStat(string q, string job) 
    { 

     try 
     { 
      //snip.... 
      attemptcount += attemptcount; 
      return ds; 

     } 
     catch 
     { 
      if (attemptcount>=2) 
      { 
      return null; 
      } 
      else 
      { 
       return GetStat(q, job); 
      } 

     } 

    } 
} 
+1

對這種方法要非常謹慎,它不會「嵌套」。假設您有一個低級方法,在放棄之前重試五次操作。呼叫者在放棄之前重試五次。呼叫者在放棄之前重試五次。突然之間,你放棄之前實際上正在重試125。我們已經有了真實世界的情況,那些應該在一秒鐘內返回錯誤代碼的代碼實際上坐在深度嵌套的重試中超過一週,似乎掛起了應用程序。快速失敗並讓用戶決定何時重試通常會更好。 – 2009-06-26 16:31:16

回答

1
public class ScEngine 
{ 
    public DataSet GetStat(string q, string job) 
    { 
     int attemptCount; 
     while(attemptCount < 2) 
     { 
      try 
      { 
       attemptCount++; 
       var ds = ...//web service call 
       return ds; 
      } 
      catch {} 
     } 
     //log the error 
     return null; 
    } 
} 
1

您忘了增加attemptcount。另外,如果在第二次運行時出現任何錯誤,它將不會被捕獲(因此成爲未處理的異常)。

+0

此外,應該嘗試count> = 2,否則它會嘗試3次...... – RedFilter 2009-06-26 12:02:26

+0

實際上,第二次運行*上的錯誤將被捕獲,因爲它會在第二次try/catch中執行,因爲他調用GetStat方法。 – 2009-06-26 12:27:01

0

我不會爲了重試而遞歸。另外,我不會理解並忽略所有例外情況。我會了解哪些異常表明應該重試的錯誤,並且會抓住那些錯誤。正如你的代碼所代表的,你將會忽略嚴重的錯誤。

0

你不想這樣解決它。您只會在服務器上增加更多負載並導致更多超時。

您可以增加Web服務超時時間via httpRuntime。 Web服務通常會在一次調用中返回大量數據,所以我發現自己經常這樣做。不要忘記增加客戶端在客戶端等待的時間。

0

這是一個不使用遞歸但達到相同結果的版本。它還包含一個延遲,這樣您可以在服務器打嗝時給服務器恢復時間。

/// <summary> 
    /// The maximum amount of attempts to use before giving up on an update, delete or create 
    /// </summary> 
    private const int MAX_ATTEMPTS = 2; 

    /// <summary> 
    /// Attempts to execute the specified delegate with the specified arguments. 
    /// </summary> 
    /// <param name="operation">The operation to attempt.</param> 
    /// <param name="arguments">The arguments to provide to the operation.</param> 
    /// <returns>The result of the operation if there are any.</returns> 
    public static object attemptOperation(Delegate operation, params object[] arguments) 
    { 
     //attempt the operation using the default max attempts 
     return attemptOperation(MAX_ATTEMPTS, operation, arguments); 
    } 

    /// <summary> 
    /// Use for creating a random delay between retry attempts. 
    /// </summary> 
    private static Random random = new Random(); 

    /// <summary> 
    /// Attempts to execute the specified delegate with the specified arguments. 
    /// </summary> 
    /// <param name="operation">The operation to attempt.</param> 
    /// <param name="arguments">The arguments to provide to the operation.</param> 
    /// <param name="maxAttempts">The number of times to attempt the operation before giving up.</param> 
    /// <returns>The result of the operation if there are any.</returns> 
    public static object attemptOperation(int maxAttempts, Delegate operation, params object [] arguments) 
    { 
     //set our initial attempt count 
     int attemptCount = 1; 

     //set the default result 
     object result = null; 

     //we've not succeeded yet 
     bool success = false; 

     //keep trying until we get a result 
     while (success == false) 
     { 
      try 
      { 
       //attempt the operation and get the result 
       result = operation.DynamicInvoke(arguments); 
       //we succeeded if there wasn't an exception 
       success = true; 
      } 
      catch 
      { 
       //if we've got to the max attempts and still have an error, give up an rethrow it 
       if (attemptCount++ == maxAttempts) 
       { 
        //propogate the exception 
        throw; 
       } 
       else 
       { 
        //create a random delay in milliseconds 
        int randomDelayMilliseconds = random.Next(1000, 5000); 
        //sleep for the specified amount of milliseconds 
        System.Threading.Thread.Sleep(randomDelayMilliseconds); 
       } 
      } 
     } 

     //return the result 
     return result; 
    }