【问题标题】:Why does HttpClient continue to fail during subsequent retries using Polly?为什么 HttpClient 在后续使用 Polly 重试期间继续失败?
【发布时间】:2018-03-29 01:27:04
【问题描述】:

我有几种方法需要某种类型的互联网连接。如果连接失败,我想在失败之前重试该方法一段时间。由于应用程序可以在等待成功响应的同时愉快地继续运行,因此我想异步执行此操作。

我正在使用Polly (5.3.1) 来实现利用Tasks 的异步重试逻辑。

我通过禁用我的 Wi-Fi 启动该过程并在重试窗口期间启用它来模拟断开连接。我期待在再次启用我的连接后,该方法在重试时会成功,我所看到的是该方法继续抛出HttpRequestException,就好像连接断开一样,直到重试完成,此时它抛出给调用者.
如果我在正常启用 Wi-Fi 的情况下启动该方法,它会立即成功。

// Get the HTML of a web page 'async'
public async Task<string> GetHtmlAsync(string url)
{
    using (var client = new HttpClient())
    using (var response = await client.GetAsync(url))
    {
        response.EnsureSuccessStatusCode();
        using (var content = response.Content)
        {
            return await content.ReadAsStringAsync();
        }
    }
}

// Wrapper for Polly to create an async retry policy
public async Task<TResult> RetryAsync<TResult, TException>(Task<TResult> task, int retries, int seconds) where TException : Exception
{
    return await Policy
               .Handle<TException>()
               .WaitAndRetryAsync(retries, wait => TimeSpan.FromSeconds(seconds))
               .ExecuteAsync(async () => await task);
}

// Call the method, it will retry 12 times with a gap of 5 seconds between tries
var html = await RetryAsync<string, HttpRequestException>(GetHtmlAsync("https://www.google.co.uk"), 12, 5);

为什么即使我的连接已启用并在后续重试期间正常工作,该方法仍会继续失败?

【问题讨论】:

  • 你不应该创建这么多的 HttpClient 实例。从长远来看,这将导致问题。创建一个实例并重用它。
  • @NKosi 你是基于我在这里展示的 5 秒重试还是重新创建HttpClient 的成本通常很高?我应该指出,为了排除故障,重试时间很短,实际上我可能会在两次尝试之间等待至少 30 秒。
  • 更多的是为每个客户端创建的底层 TCP 连接
  • @Nkosi 太棒了,谢谢。我不知道。会去读一读。

标签: c# asynchronous task-parallel-library polly


【解决方案1】:

它随后会失败,因为您没有重新执行任何操作。 Task 表示异步执行的未来结果。订阅它只会给你结果,它不会重新运行代码。

把它想象成一个你已经启动的鸡蛋计时器,你可以传递它,每个人都可以看到它是否完成,但如果它已经完成,他们会立即看到。在你的情况下,因为它第一次失败,它立即失败了后续检查。

你想要的是重试调用:

public async Task<string> GetHtmlAsync(string url)
{
    using (var client = new HttpClient())
    using (var response = await client.GetAsync(url))
    {
        response.EnsureSuccessStatusCode();
        using (var content = response.Content)
        {
            return await content.ReadAsStringAsync();
        }
    }
}

// Wrapper for Polly to create an async retry policy
public async Task<TResult> RetryAsync<TResult, TException>(
    Func<Task<TResult>> taskInitiator, int retries, int seconds) where TException : Exception
{
    return await Policy
               .Handle<TException>()
               .WaitAndRetryAsync(retries, wait => TimeSpan.FromSeconds(seconds))
               .ExecuteAsync(async () => await taskInitiator());
}

// Call the method, it will retry 12 times with a gap of 5 seconds between tries
var html = await RetryAsync<string, HttpRequestException>(
    () => GetHtmlAsync("https://www.google.co.uk"), 12, 5);

【讨论】:

  • 太棒了,这很有意义。我很生气它如此明显,我想我已经盲了代码。
  • +1。与最终在这个几乎相同的问题上发现的问题相同:stackoverflow.com/questions/46414976/…。但是通过在 q,equalsk 的第一个版本中发布您的完整代码,您会立即得到正确的答案。 @richardszalay:鸡蛋计时器的好比喻!
猜你喜欢
  • 1970-01-01
  • 2019-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多