protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage requestMessage, CancellationToken cancellationToken) { HttpResponseMessage response = null; int backOffInSec = 1; int totalRetryTime = 0; int maxDefaultBackoff = 16; ServicePoint p = ServicePointManager.FindServicePoint(requestMessage.RequestUri); p.Expect100Continue = false; // Saves about 100 ms per request p.UseNagleAlgorithm = false; // Saves about 200 ms per request p.ConnectionLimit = 20; // Default value is 2, we need more connections for performing multiple parallel queries TimeSpan httpTimeout = (TimeSpan)requestMessage.Properties[SFRestRequest.HTTP_REQUEST_TIMEOUT_KEY]; TimeSpan restTimeout = (TimeSpan)requestMessage.Properties[SFRestRequest.REST_REQUEST_TIMEOUT_KEY]; if (logger.IsDebugEnabled()) { logger.Debug("Http request timeout : " + httpTimeout); logger.Debug("Rest request timeout : " + restTimeout); } CancellationTokenSource childCts = null; UriUpdater updater = new UriUpdater(requestMessage.RequestUri); while (true) { try { childCts = null; if (!httpTimeout.Equals(Timeout.InfiniteTimeSpan)) { childCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); childCts.CancelAfter(httpTimeout); } response = await base.SendAsync(requestMessage, childCts == null? cancellationToken : childCts.Token).ConfigureAwait(false); } catch (Exception e) { if (cancellationToken.IsCancellationRequested) { logger.Debug("SF rest request timeout or explicit cancel called."); cancellationToken.ThrowIfCancellationRequested(); } else if (childCts != null && childCts.Token.IsCancellationRequested) { logger.Warn("Http request timeout. Retry the request"); totalRetryTime += (int)httpTimeout.TotalSeconds; } else { //TODO: Should probably check to see if the error is recoverable or transient. logger.Warn("Error occurred during request, retrying...", e); } } if (response != null) { if (response.IsSuccessStatusCode) { return(response); } else { logger.Debug($"Failed Response: {response.ToString()}"); bool isRetryable = isRetryableHTTPCode((int)response.StatusCode); if (!isRetryable) { // No need to keep retrying, stop here return(response); } } } else { logger.Info("Response returned was null."); } requestMessage.RequestUri = updater.Update(); logger.Debug($"Sleep {backOffInSec} seconds and then retry the request"); Thread.Sleep(backOffInSec * 1000); totalRetryTime += backOffInSec; backOffInSec = backOffInSec >= maxDefaultBackoff ? maxDefaultBackoff : backOffInSec * 2; if (totalRetryTime + backOffInSec > restTimeout.TotalSeconds) { // No need to wait more than necessary if it can be avoided. // If the rest timeout will be reached before the next back-off, // use a smaller one to give the Rest request a chance to timeout early backOffInSec = Math.Max(1, (int)restTimeout.TotalSeconds - totalRetryTime - 1); } } }
protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage requestMessage, CancellationToken cancellationToken) { HttpResponseMessage response = null; int backOffInSec = 1; TimeSpan httpTimeout = (TimeSpan)requestMessage.Properties["TIMEOUT_PER_HTTP_REQUEST"]; CancellationTokenSource childCts = null; UriUpdater updater = new UriUpdater(requestMessage.RequestUri); while (true) { try { childCts = null; if (!httpTimeout.Equals(Timeout.InfiniteTimeSpan)) { childCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); childCts.CancelAfter(httpTimeout); } response = await base.SendAsync(requestMessage, childCts == null? cancellationToken : childCts.Token).ConfigureAwait(false); } catch (Exception e) { if (cancellationToken.IsCancellationRequested) { logger.Debug("SF rest request timeout."); cancellationToken.ThrowIfCancellationRequested(); } else if (childCts != null && childCts.Token.IsCancellationRequested) { logger.Warn("Http request timeout. Retry the request"); } else { //TODO: Should probably check to see if the error is recoverable or transient. logger.Warn("Error occurred during request, retrying...", e); } } if (response != null) { if (response.IsSuccessStatusCode) { return(response); } logger.Debug($"Failed Response: {response.ToString()}"); } else { logger.Info("Response returned was null."); } requestMessage.RequestUri = updater.Update(); logger.Debug($"Sleep {backOffInSec} seconds and then retry the request"); Thread.Sleep(backOffInSec * 1000); backOffInSec = backOffInSec >= 16 ? 16 : backOffInSec * 2; } }