2017-10-17 106 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! –