我知道有更好的方法来做到这一点,我确信我的机制实际上是错误的,如果它一直失败会崩溃。除了我的方式之外,重试机制是否有更好的实践?
由于我依赖于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);
}
答案 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;
}
}
}
}