Skip to content

Commit 2c02990

Browse files
committed
Renamed some fields. Added exponential calculator
1 parent e4e7dff commit 2c02990

File tree

4 files changed

+41
-15
lines changed

4 files changed

+41
-15
lines changed

src/SendGrid/Reliability/ReliabilitySettings.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ public ReliabilitySettings()
2121
}
2222

2323
/// <summary>
24-
/// Gets or sets the number of retries to execute against when sending an HTTP Request before throwing an exception. Defaults to 0 (no retries, you must explicitly enable)
24+
/// Gets or sets the maximum number of retries to execute against when sending an HTTP Request before throwing an exception. Defaults to 0 (no retries, you must explicitly enable)
2525
/// </summary>
26-
public int RetryCount
26+
public int MaximumNumberOfRetries
2727
{
2828
get
2929
{
@@ -39,7 +39,7 @@ public int RetryCount
3939

4040
if (value > 5)
4141
{
42-
throw new ArgumentException("The maximum number of retries is 5");
42+
throw new ArgumentException("The maximum number of retries that can be attempted is 5");
4343
}
4444

4545
this.retryCount = value;

src/SendGrid/Reliability/RetryDelegatingHandler.cs

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
/// </summary>
1212
public class RetryDelegatingHandler : DelegatingHandler
1313
{
14-
private static List<int> retriableStatusCodes = new List<int>() { 500, 502, 503, 504 };
14+
private static readonly List<int> RetriableStatusCodes = new List<int>() { 500, 502, 503, 504 };
1515

1616
private readonly ReliabilitySettings settings;
1717

@@ -32,12 +32,15 @@ public RetryDelegatingHandler(HttpMessageHandler innerHandler, ReliabilitySettin
3232

3333
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
3434
{
35-
if (this.settings.RetryCount == 0)
35+
if (this.settings.MaximumNumberOfRetries == 0)
3636
{
3737
return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
3838
}
3939

4040
HttpResponseMessage responseMessage = null;
41+
var backOffCalculator = new ExponentialBackOffCalculator(settings.RetryInterval);
42+
43+
var waitFor = settings.RetryInterval;
4144
var numberOfAttempts = 0;
4245
var sent = false;
4346

@@ -55,25 +58,27 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
5558
{
5659
numberOfAttempts++;
5760

58-
if (numberOfAttempts > this.settings.RetryCount)
61+
if (numberOfAttempts > this.settings.MaximumNumberOfRetries)
5962
{
6063
throw new TimeoutException();
6164
}
6265

6366
// ReSharper disable once MethodSupportsCancellation, cancel will be indicated on the token
64-
await Task.Delay(this.settings.RetryInterval).ConfigureAwait(false);
67+
await Task.Delay(waitFor).ConfigureAwait(false);
6568
}
6669
catch (HttpRequestException)
6770
{
6871
numberOfAttempts++;
6972

70-
if (numberOfAttempts > this.settings.RetryCount)
73+
if (numberOfAttempts > this.settings.MaximumNumberOfRetries)
7174
{
7275
throw;
7376
}
7477

75-
await Task.Delay(this.settings.RetryInterval).ConfigureAwait(false);
78+
await Task.Delay(waitFor).ConfigureAwait(false);
7679
}
80+
81+
waitFor = backOffCalculator.GetNextWaitInterval(numberOfAttempts);
7782
}
7883

7984
return responseMessage;
@@ -83,10 +88,31 @@ private static void ThrowHttpRequestExceptionIfResponseCodeIsRetriable(HttpRespo
8388
{
8489
int statusCode = (int)responseMessage.StatusCode;
8590

86-
if (retriableStatusCodes.Contains(statusCode))
91+
if (RetriableStatusCodes.Contains(statusCode))
8792
{
8893
throw new HttpRequestException(string.Format("Http status code '{0}' indicates server error", statusCode));
8994
}
9095
}
96+
97+
private class ExponentialBackOffCalculator
98+
{
99+
private TimeSpan baseInterval;
100+
101+
private readonly Random random = new Random();
102+
103+
public ExponentialBackOffCalculator(TimeSpan baseInterval)
104+
{
105+
this.baseInterval = baseInterval;
106+
}
107+
108+
public TimeSpan GetNextWaitInterval(int numberOfAttempts)
109+
{
110+
var interval = this.baseInterval.TotalMilliseconds + (Math.Pow(2, numberOfAttempts) * 1000);
111+
112+
var randomDelay = this.random.Next(0, 1000);
113+
114+
return TimeSpan.FromMilliseconds(interval + randomDelay);
115+
}
116+
}
91117
}
92118
}

tests/SendGrid.Tests/Integration.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6141,7 +6141,7 @@ public async Task TestRetryBehaviourThrowsTimeoutException()
61416141
var options = new SendGridClientOptions
61426142
{
61436143
ApiKey = fixture.apiKey,
6144-
ReliabilitySettings = { RetryCount = 1 },
6144+
ReliabilitySettings = { MaximumNumberOfRetries = 1 },
61456145
Host = "http://localhost:4010"
61466146
};
61476147

@@ -6169,7 +6169,7 @@ public async Task TestRetryBehaviourSucceedsOnSecondAttempt()
61696169
var options = new SendGridClientOptions
61706170
{
61716171
ApiKey = fixture.apiKey,
6172-
ReliabilitySettings = { RetryCount = 1 }
6172+
ReliabilitySettings = { MaximumNumberOfRetries = 1 }
61736173
};
61746174

61756175
var id = "test_url_param";

tests/SendGrid.Tests/Reliability/RetryDelegatingHandlerTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public RetryDelegatingHandlerTests()
1717
{
1818
var reliabilitySettings = new ReliabilitySettings
1919
{
20-
RetryCount = 1
20+
MaximumNumberOfRetries = 1
2121
};
2222
innerHandler = new RetryTestBehaviourDelegatingHandler();
2323
client = new HttpClient(new RetryDelegatingHandler(innerHandler, reliabilitySettings))
@@ -119,15 +119,15 @@ public void ReliabilitySettingsShouldNotAllowNegativeRetryCount()
119119
{
120120
var settings = new ReliabilitySettings();
121121

122-
Assert.Throws<ArgumentException>(() => settings.RetryCount = -1);
122+
Assert.Throws<ArgumentException>(() => settings.MaximumNumberOfRetries = -1);
123123
}
124124

125125
[Fact]
126126
public void ReliabilitySettingsShouldNotAllowRetryCountGreaterThan5()
127127
{
128128
var settings = new ReliabilitySettings();
129129

130-
Assert.Throws<ArgumentException>(() => settings.RetryCount = 6);
130+
Assert.Throws<ArgumentException>(() => settings.MaximumNumberOfRetries = 6);
131131
}
132132

133133
[Fact]

0 commit comments

Comments
 (0)