在WebClient机制中限制429个错误的连接,最佳做法是什么?

时间:2018-04-28 06:22:10

标签: c# .net

我知道有更好的方法来做到这一点,我确信我的机制实际上是错误的,如果它一直失败会崩溃。除了我的方式之外,重试机制是否有更好的实践?

由于我依赖于Web客户端提供的响应,因此我绝不想错过此Web客户端的响应。我正在转换一个网站新系统的列表。我知道流量充斥会导致429错误(连接太多)所以正确的做法是节流,对吗?

这是我的机制。

public static string GetUsernameFromId(long userId)
{
    using (var client = new WebClient())
    {
        try
        {
            // removed business logic, minimal example
        }
        catch (WebException we)
        {
            if (we.Message.Contains("429"))
            {
                return ThrottleConnections(userId);
            }

            throw;
        }
    }
}

public static string ThrottleConnections(long userId)
{
    System.Threading.Thread.Sleep(1 * 60 * 1000);
    return GetUsernameFromId(userId);
}

2 个答案:

答案 0 :(得分:0)

使用Thread.Sleep几乎不是一个好主意,最好使用计时器或await Task.Delay(...),因为它不会阻止。

您最好的选择是使用能够以深思熟虑的方式提供重试等的库。例如,Polly是一个众所周知的库。它也支持基于时间的重试,请参阅the docs

// Retry, waiting a specified duration between each retry
Policy
.Handle<SomeExceptionType>()
.WaitAndRetry(new[]
{
    TimeSpan.FromSeconds(1),
    TimeSpan.FromSeconds(2),
    TimeSpan.FromSeconds(3)
});

如果回复有Retry-After标头,您可以use that as well

  

某些系统指定在重试之前等待多长时间,作为返回的故障响应的一部分。这通常表示为带有429响应代码的Retry-After标头。

     

这可以通过使用WaitAndRetry / Forever / Async(...)重载来处理,其中sleepDurationProvider将处理的错误/异常作为输入参数(示例重载;讨论和示例代码)。

     

某些SDK在自定义响应或异常中包装RetryAfter:例如,基础Azure CosmosDB体系结构使用x-ms-retry-after-ms标头发送429响应代码(请求太多),但Azure客户端SDK表示这回到调用代码,方法是抛出带有RetryAfter属性的DocumentClientException。可以使用相同的重载来处理这些。

如果您不想使用外部库,至少可以浏览源代码以了解如何处理重试。

答案 1 :(得分:0)

是的,我不会用递归来做这件事,它要求麻烦。

这可能会更好,在一个带有重试次数和限制以及一些不错的asycnrony的while循环中,我也留下了很多想象力,你可能想要抛出最大重试次数

public static async Task<string> GetUsernameFromId(long userId)
{
   var retries = 0;
   while (retries++ < MaxRetries)
   {

      using (var client = new WebClient())
      {
         try
         {
            ///await client.OpenReadTaskAsync();
            ///blah
            /// 
            break;
         }
         catch (WebException we)
         {
            if (!we.Message.Contains("429"))
            {
               await Task.Delay(waitTime);
               continue;
            }

            throw;
         }
      }
   }
}