private async Task <HttpResponse> ExecuteWithRetryAsync( Uri endpoint, IDictionary <string, string> headers, HttpContent body, HttpMethod method, ICoreLogger logger, bool doNotThrow = false, bool retry = true) { Exception timeoutException = null; bool isRetryable = false; bool is5xxError = false; HttpResponse response = null; try { HttpContent clonedBody = body; if (body != null) { // Since HttpContent would be disposed by underlying client.SendAsync(), // we duplicate it so that we will have a copy in case we would need to retry clonedBody = await CloneHttpContentAsync(body).ConfigureAwait(false); } response = await ExecuteAsync(endpoint, headers, clonedBody, method).ConfigureAwait(false); if (response.StatusCode == HttpStatusCode.OK) { return(response); } logger.Info(string.Format(CultureInfo.InvariantCulture, MsalErrorMessage.HttpRequestUnsuccessful, (int)response.StatusCode, response.StatusCode)); is5xxError = (int)response.StatusCode >= 500 && (int)response.StatusCode < 600; isRetryable = is5xxError && !HasRetryAfterHeader(response); } catch (TaskCanceledException exception) { logger.Error("The HTTP request failed or it was canceled. " + exception.Message); isRetryable = true; timeoutException = exception; } if (isRetryable && retry) { logger.Info("Retrying one more time.."); await Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false); return(await ExecuteWithRetryAsync( endpoint, headers, body, method, logger, doNotThrow, retry : false).ConfigureAwait(false)); } logger.Warning("Request retry failed."); if (timeoutException != null) { throw new MsalServiceException( MsalError.RequestTimeout, "Request to the endpoint timed out.", timeoutException); } if (doNotThrow) { return(response); } if (is5xxError) { throw MsalServiceExceptionFactory.FromHttpResponse( MsalError.ServiceNotAvailable, "Service is unavailable to process the request", response); } return(response); }