2009-06-26 84 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; 
    }