diff --git a/src/Jackett.Common/Indexers/BaseIndexer.cs b/src/Jackett.Common/Indexers/BaseIndexer.cs index 83ffb3253..2556c7fe6 100644 --- a/src/Jackett.Common/Indexers/BaseIndexer.cs +++ b/src/Jackett.Common/Indexers/BaseIndexer.cs @@ -14,6 +14,7 @@ using Newtonsoft.Json; using Newtonsoft.Json.Linq; using NLog; using Polly; +using Polly.Retry; using static Jackett.Common.Models.IndexerConfig.ConfigurationData; namespace Jackett.Common.Indexers @@ -416,31 +417,41 @@ namespace Jackett.Common.Indexers } } - private AsyncPolicy RetryPolicy + private ResiliencePipeline RetryStrategy { get { - // Configure the retry policy - int attemptNumber = 1; - var retryPolicy = Policy - .HandleResult(r => (int)r.Status >= 500) - .Or() - .WaitAndRetryAsync( - NumberOfRetryAttempts, - retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt) / 4), - onRetry: (exception, timeSpan, context) => + var retryPipeline = new ResiliencePipelineBuilder() + .AddRetry(new RetryStrategyOptions + { + ShouldHandle = args => args.Outcome switch { - if (exception.Result == null) + { Result: { HasHttpServerError: true } } => PredicateResult.True(), + { Result: { Status: System.Net.HttpStatusCode.RequestTimeout } } => PredicateResult.True(), + { Exception: { } } => PredicateResult.True(), + _ => PredicateResult.False() + }, + Delay = TimeSpan.FromSeconds(2), + MaxRetryAttempts = NumberOfRetryAttempts, + BackoffType = DelayBackoffType.Exponential, + UseJitter = true, + OnRetry = args => + { + if (args.Outcome.Exception != null) { - logger.Warn($"Request to {Name} failed with exception '{exception.Exception.Message}'. Retrying in {timeSpan.TotalSeconds}s... (Attempt {attemptNumber} of {NumberOfRetryAttempts})."); + logger.Warn("Request to {0} failed with exception '{1}'. Retrying in {2}s.", Name, args.Outcome.Exception.Message, args.RetryDelay.TotalSeconds); } else { - logger.Warn($"Request to {Name} failed with status {exception.Result.Status}. Retrying in {timeSpan.TotalSeconds}s... (Attempt {attemptNumber} of {NumberOfRetryAttempts})."); + logger.Warn("Request to {0} failed with status {1}. Retrying in {2}s.", Name, args.Outcome.Result?.Status, args.RetryDelay.TotalSeconds); } - attemptNumber++; - }); - return retryPolicy; + + return default; + } + }) + .Build(); + + return retryPipeline; } } @@ -531,9 +542,9 @@ namespace Jackett.Common.Indexers string referer = null, IEnumerable> data = null, Dictionary headers = null, string rawbody = null, bool? emulateBrowser = null) { - return await RetryPolicy.ExecuteAsync(async () => - await RequestWithCookiesAsync(url, cookieOverride, method, referer, data, headers, rawbody, emulateBrowser) - ); + return await RetryStrategy + .ExecuteAsync(async _ => await RequestWithCookiesAsync(url, cookieOverride, method, referer, data, headers, rawbody, emulateBrowser)) + .ConfigureAwait(false); } protected virtual async Task RequestWithCookiesAsync( diff --git a/src/Jackett.Common/Jackett.Common.csproj b/src/Jackett.Common/Jackett.Common.csproj index 88fd8415d..d0444019b 100644 --- a/src/Jackett.Common/Jackett.Common.csproj +++ b/src/Jackett.Common/Jackett.Common.csproj @@ -24,7 +24,7 @@ - + diff --git a/src/Jackett.Common/Utils/Clients/WebResult.cs b/src/Jackett.Common/Utils/Clients/WebResult.cs index 893e063e5..a11ca1ae7 100644 --- a/src/Jackett.Common/Utils/Clients/WebResult.cs +++ b/src/Jackett.Common/Utils/Clients/WebResult.cs @@ -66,6 +66,10 @@ namespace Jackett.Common.Utils.Clients set => _contentString = value; } + public bool HasHttpError => (int)Status >= 400; + + public bool HasHttpServerError => (int)Status >= 500; + public bool IsRedirect => Status == HttpStatusCode.Redirect || Status == HttpStatusCode.RedirectKeepVerb || Status == HttpStatusCode.RedirectMethod ||