22{
33 using System ;
44 using System . Collections . Generic ;
5+ using System . Net ;
56 using System . Net . Http ;
67 using System . Threading ;
78 using System . Threading . Tasks ;
1112 /// </summary>
1213 public class RetryDelegatingHandler : DelegatingHandler
1314 {
14- private static readonly List < int > RetriableStatusCodes = new List < int > ( ) { 500 , 502 , 503 , 504 } ;
15+ private static readonly List < HttpStatusCode > RetriableServerErrorStatusCodes =
16+ new List < HttpStatusCode > ( )
17+ {
18+ HttpStatusCode . InternalServerError ,
19+ HttpStatusCode . BadGateway ,
20+ HttpStatusCode . ServiceUnavailable ,
21+ HttpStatusCode . GatewayTimeout
22+ } ;
1523
1624 private readonly ReliabilitySettings settings ;
1725
@@ -26,6 +34,11 @@ public RetryDelegatingHandler(ReliabilitySettings settings)
2634 {
2735 }
2836
37+ /// <summary>
38+ /// Initializes a new instance of the <see cref="RetryDelegatingHandler"/> class.
39+ /// </summary>
40+ /// <param name="innerHandler">A HttpMessageHandler instance to set as the innner handler</param>
41+ /// <param name="settings">A ReliabilitySettings instance</param>
2942 public RetryDelegatingHandler ( HttpMessageHandler innerHandler , ReliabilitySettings settings )
3043 : base ( innerHandler )
3144 {
@@ -41,12 +54,13 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
4154
4255 HttpResponseMessage responseMessage = null ;
4356
44- var waitFor = settings . RetryInterval ;
4557 var numberOfAttempts = 0 ;
4658 var sent = false ;
4759
4860 while ( ! sent )
4961 {
62+ var waitFor = this . GetNextWaitInterval ( numberOfAttempts ) ;
63+
5064 try
5165 {
5266 responseMessage = await base . SendAsync ( request , cancellationToken ) . ConfigureAwait ( false ) ;
@@ -78,30 +92,33 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
7892
7993 await Task . Delay ( waitFor ) . ConfigureAwait ( false ) ;
8094 }
81-
82- waitFor = GetNextWaitInterval ( numberOfAttempts ) ;
8395 }
8496
8597 return responseMessage ;
8698 }
8799
88100 private static void ThrowHttpRequestExceptionIfResponseCodeCanBeRetried ( HttpResponseMessage responseMessage )
89101 {
90- int statusCode = ( int ) responseMessage . StatusCode ;
91-
92- if ( RetriableStatusCodes . Contains ( statusCode ) )
102+ if ( RetriableServerErrorStatusCodes . Contains ( responseMessage . StatusCode ) )
93103 {
94- throw new HttpRequestException ( string . Format ( "Http status code '{0}' indicates server error" , statusCode ) ) ;
104+ throw new HttpRequestException ( string . Format ( "Http status code '{0}' indicates server error" , responseMessage . StatusCode ) ) ;
95105 }
96106 }
97107
98108 private TimeSpan GetNextWaitInterval ( int numberOfAttempts )
99109 {
100- var interval = this . settings . RetryInterval . TotalMilliseconds + ( Math . Pow ( 2 , numberOfAttempts ) * 1000 ) ;
110+ var randomDelay = this . random . Next ( 0 , 500 ) ;
111+
112+ if ( numberOfAttempts == 0 )
113+ {
114+ return TimeSpan . FromMilliseconds ( this . settings . RetryInterval . TotalMilliseconds + randomDelay ) ;
115+ }
116+
117+ var exponentialIncrease = Math . Pow ( 2 , numberOfAttempts ) * 1000 ;
101118
102- var randomDelay = this . random . Next ( 0 , 1000 ) ;
119+ var actualIncrease = TimeSpan . FromMilliseconds ( this . settings . RetryInterval . TotalMilliseconds + exponentialIncrease + randomDelay ) ;
103120
104- return TimeSpan . FromMilliseconds ( interval + randomDelay ) ;
121+ return actualIncrease ;
105122 }
106123 }
107124}
0 commit comments