2017-10-17 153 views
4

我有几种方法需要某种互联网连接。如果连接失败,我想在失败之前重试该方法一段时间。由于应用程序可以在等待成功响应的同时继续运行,我希望异步执行此操作。为什么在使用Polly的后续重试中HttpClient会继续失败?

我使用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); 

为什么该方法继续即使失败,虽然我的连接已启用,并在随后的重试工作?

+0

你不应该创建一个HttpClient这么多的实例。这将导致长期的问题。创建一个实例并重用它。 – Nkosi

+0

@NKosi你是基于在这里显示的5秒重试,还是通常是昂贵的重新创建'HttpClient'?我应该指出,这个重试只是为了排除故障,实际上我可能会在尝试之间等待至少30秒。 – Equalsk

+0

https://stackoverflow.com/questions/24043679/how-many-httpclients-should-i-create – Nkosi

回答

5

它随后失败,因为您没有重新执行任何操作。 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); 
+0

真棒,这是非常有意义的。我很恼火,这非常明显,我认为我已经失去了代码。 – Equalsk

+0

+1。同样的问题,最终发现在这个几乎相同的问题上:https://stackoverflow.com/questions/46414976/c-sharp-polly-async-await-wait-for-user-confirmation-before-retry/46421518#46421518。但是通过在q,equalsk的第一个版本中发布完整代码,您马上就能得到正确的答案。 @richardszalay:鸡蛋计时器的伟大metephor! –

相关问题