using NLog; using System; using System.Linq; using System.Net; using System.Net.Http; using System.Threading; using System.Threading.Tasks; namespace Sony.Filtr.Utility.HttpHandlers { public class RetryHttpHandler : DelegatingHandler { private readonly int MaxRetries; private readonly Logger Logger; private readonly TimeSpan Timeout; private readonly TimeSpan DelayBeforeRetry; private readonly HttpStatusCode[] NonRetryableStatusCodes = new HttpStatusCode[] { HttpStatusCode.NotFound, HttpStatusCode.Unauthorized }; public RetryHttpHandler(int maxRetries, TimeSpan timeout, TimeSpan delayBeforeRetry, HttpMessageHandler baseHandler) : base(baseHandler) { this.MaxRetries = Math.Max(maxRetries, 1); this.Logger = LogManager.GetLogger("RetryHttpHandler"); this.Timeout = timeout; this.DelayBeforeRetry = delayBeforeRetry; } protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { HttpResponseMessage lastResponse = null; Exception lastException = null; for (int i = 0; i < this.MaxRetries; ++i) { if (cancellationToken.IsCancellationRequested) { throw new TaskCanceledException($"Request {request.Method} {request.RequestUri} has been cancelled."); } HttpResponseMessage response = null; try { var cts = new CancellationTokenSource(this.Timeout); response = await base.SendAsync(request, cts.Token); if (response.IsSuccessStatusCode) { return response; } if (this.NonRetryableStatusCodes.Contains(response.StatusCode)) { return response; } this.Logger.Error($"{response.StatusCode} Retrying {i} {request.Method} {request.RequestUri} Raw response: {response.Content.ReadAsStringAsync().Result}"); lastResponse = response; } catch (Exception ex) { this.Logger.Error($"*** ERROR *** {ex.Message} Retrying {i} {request.Method} {request.RequestUri} Raw response: {response?.Content.ReadAsStringAsync().Result}"); lastException = ex; } await Task.Delay(this.DelayBeforeRetry); } if (lastResponse == null) { throw lastException; }; return lastResponse; } } }