Created
March 26, 2017 22:11
-
-
Save CESARDELATORRE/6d7f647b29e55fdc219ee1fd2babb260 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Diagnostics; | |
using System.Linq; | |
using System.Threading.Tasks; | |
namespace Microsoft.eShopOnContainers.WebMVC.Services | |
{ | |
/// <summary> | |
/// When working with cloud services and Docker containers, it's very important to always catch | |
/// TimeoutException, and retry the operation. | |
/// RetryWithExponentialBackoff makes it easy to implement such pattern. | |
/// Usage: | |
/// var retry = new RetryWithExponentialBackoff(); | |
/// await retry.RunAsync(async ()=> | |
/// { | |
/// // work with HttpClient | |
/// }); | |
/// </summary> | |
public sealed class RetryWithExponentialBackoff | |
{ | |
private readonly int maxRetries, delayMilliseconds, maxDelayMilliseconds; | |
public RetryWithExponentialBackoff(int maxRetries = 50, int delayMilliseconds = 200, int maxDelayMilliseconds = 2000) | |
{ | |
this.maxRetries = maxRetries; | |
this.delayMilliseconds = delayMilliseconds; | |
this.maxDelayMilliseconds = maxDelayMilliseconds; | |
} | |
public async Task RunAsync(Func<Task> func) | |
{ | |
ExponentialBackoff backoff = new ExponentialBackoff(this.maxRetries, this.delayMilliseconds, this.maxDelayMilliseconds); | |
retry: | |
try | |
{ | |
await func(); | |
} | |
catch (Exception ex) when (ex is TimeoutException || ex is System.Net.Http.HttpRequestException) | |
{ | |
Debug.WriteLine("Exception raised is: " + ex.GetType().ToString() + " -- Message: " + ex.Message + " -- Inner Message: " + ex.InnerException.Message); | |
await backoff.Delay(); | |
goto retry; | |
} | |
} | |
} | |
/// <summary> | |
/// Usage: | |
/// ExponentialBackoff backoff = new ExponentialBackoff(3, 10, 100); | |
/// retry: | |
/// try { | |
/// // ... | |
/// } | |
/// catch (Exception ex) { | |
/// await backoff.Delay(cancellationToken); | |
/// goto retry; | |
/// } | |
/// </summary> | |
public struct ExponentialBackoff | |
{ | |
private readonly int m_maxRetries, m_delayMilliseconds, m_maxDelayMilliseconds; | |
private int m_retries, m_pow; | |
public ExponentialBackoff(int maxRetries, int delayMilliseconds, int maxDelayMilliseconds) | |
{ | |
m_maxRetries = maxRetries; | |
m_delayMilliseconds = delayMilliseconds; | |
m_maxDelayMilliseconds = maxDelayMilliseconds; | |
m_retries = 0; | |
m_pow = 1; | |
} | |
public Task Delay() | |
{ | |
if (m_retries == m_maxRetries) | |
{ | |
throw new TimeoutException("Max retry attempts exceeded."); | |
} | |
++m_retries; | |
if (m_retries < 31) | |
{ | |
m_pow = m_pow << 1; // m_pow = Pow(2, m_retries - 1) | |
} | |
int delay = Math.Min(m_delayMilliseconds * (m_pow - 1) / 2, m_maxDelayMilliseconds); | |
return Task.Delay(delay); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This chokes on line 41 if there is no
InnerException
.