mirror of
https://github.com/Radarr/Radarr.git
synced 2024-11-04 10:02:40 +01:00
Generalized RateLimit logic to all indexers based on indexer id
Co-authored-by: Taloth Saldono <Taloth@users.noreply.github.com>
This commit is contained in:
parent
914d3764dc
commit
10205da1c3
@ -89,5 +89,38 @@ public void should_add_delay()
|
|||||||
|
|
||||||
(GetRateLimitStore()["me"] - _epoch).Should().BeGreaterOrEqualTo(TimeSpan.FromMilliseconds(100));
|
(GetRateLimitStore()["me"] - _epoch).Should().BeGreaterOrEqualTo(TimeSpan.FromMilliseconds(100));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_extend_subkey_delay()
|
||||||
|
{
|
||||||
|
GivenExisting("me", _epoch + TimeSpan.FromMilliseconds(200));
|
||||||
|
GivenExisting("me-sub", _epoch + TimeSpan.FromMilliseconds(300));
|
||||||
|
|
||||||
|
Subject.WaitAndPulse("me", "sub", TimeSpan.FromMilliseconds(100));
|
||||||
|
|
||||||
|
(GetRateLimitStore()["me-sub"] - _epoch).Should().BeGreaterOrEqualTo(TimeSpan.FromMilliseconds(400));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_honor_basekey_delay()
|
||||||
|
{
|
||||||
|
GivenExisting("me", _epoch + TimeSpan.FromMilliseconds(200));
|
||||||
|
GivenExisting("me-sub", _epoch + TimeSpan.FromMilliseconds(0));
|
||||||
|
|
||||||
|
Subject.WaitAndPulse("me", "sub", TimeSpan.FromMilliseconds(100));
|
||||||
|
|
||||||
|
(GetRateLimitStore()["me-sub"] - _epoch).Should().BeGreaterOrEqualTo(TimeSpan.FromMilliseconds(200));
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void should_not_extend_basekey_delay()
|
||||||
|
{
|
||||||
|
GivenExisting("me", _epoch + TimeSpan.FromMilliseconds(200));
|
||||||
|
GivenExisting("me-sub", _epoch + TimeSpan.FromMilliseconds(100));
|
||||||
|
|
||||||
|
Subject.WaitAndPulse("me", "sub", TimeSpan.FromMilliseconds(100));
|
||||||
|
|
||||||
|
(GetRateLimitStore()["me"] - _epoch).Should().BeCloseTo(TimeSpan.FromMilliseconds(200));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,7 +109,7 @@ private HttpResponse ExecuteRequest(HttpRequest request, CookieContainer cookieC
|
|||||||
|
|
||||||
if (request.RateLimit != TimeSpan.Zero)
|
if (request.RateLimit != TimeSpan.Zero)
|
||||||
{
|
{
|
||||||
_rateLimitService.WaitAndPulse(request.Url.Host, request.RateLimit);
|
_rateLimitService.WaitAndPulse(request.Url.Host, request.RateLimitKey, request.RateLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
_logger.Trace(request);
|
_logger.Trace(request);
|
||||||
|
@ -44,6 +44,7 @@ public HttpRequest(string url, HttpAccept httpAccept = null)
|
|||||||
public bool StoreResponseCookie { get; set; }
|
public bool StoreResponseCookie { get; set; }
|
||||||
public TimeSpan RequestTimeout { get; set; }
|
public TimeSpan RequestTimeout { get; set; }
|
||||||
public TimeSpan RateLimit { get; set; }
|
public TimeSpan RateLimit { get; set; }
|
||||||
|
public string RateLimitKey { get; set; }
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
|
@ -2,12 +2,14 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using NLog;
|
using NLog;
|
||||||
using NzbDrone.Common.Cache;
|
using NzbDrone.Common.Cache;
|
||||||
|
using NzbDrone.Common.Extensions;
|
||||||
|
|
||||||
namespace NzbDrone.Common.TPL
|
namespace NzbDrone.Common.TPL
|
||||||
{
|
{
|
||||||
public interface IRateLimitService
|
public interface IRateLimitService
|
||||||
{
|
{
|
||||||
void WaitAndPulse(string key, TimeSpan interval);
|
void WaitAndPulse(string key, TimeSpan interval);
|
||||||
|
void WaitAndPulse(string key, string subKey, TimeSpan interval);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class RateLimitService : IRateLimitService
|
public class RateLimitService : IRateLimitService
|
||||||
@ -23,9 +25,37 @@ public RateLimitService(ICacheManager cacheManager, Logger logger)
|
|||||||
|
|
||||||
public void WaitAndPulse(string key, TimeSpan interval)
|
public void WaitAndPulse(string key, TimeSpan interval)
|
||||||
{
|
{
|
||||||
var waitUntil = _rateLimitStore.AddOrUpdate(key,
|
WaitAndPulse(key, null, interval);
|
||||||
(s) => DateTime.UtcNow + interval,
|
}
|
||||||
(s, i) => new DateTime(Math.Max(DateTime.UtcNow.Ticks, i.Ticks), DateTimeKind.Utc) + interval);
|
|
||||||
|
public void WaitAndPulse(string key, string subKey, TimeSpan interval)
|
||||||
|
{
|
||||||
|
var waitUntil = DateTime.UtcNow.Add(interval);
|
||||||
|
|
||||||
|
if (subKey.IsNotNullOrWhiteSpace())
|
||||||
|
{
|
||||||
|
// Expand the base key timer, but don't extend it beyond now+interval.
|
||||||
|
var baseUntil = _rateLimitStore.AddOrUpdate(key,
|
||||||
|
(s) => waitUntil,
|
||||||
|
(s, i) => new DateTime(Math.Max(waitUntil.Ticks, i.Ticks), DateTimeKind.Utc));
|
||||||
|
|
||||||
|
if (baseUntil > waitUntil)
|
||||||
|
{
|
||||||
|
waitUntil = baseUntil;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the full key
|
||||||
|
var combinedKey = key + "-" + subKey;
|
||||||
|
waitUntil = _rateLimitStore.AddOrUpdate(combinedKey,
|
||||||
|
(s) => waitUntil,
|
||||||
|
(s, i) => new DateTime(Math.Max(waitUntil.Ticks, i.Add(interval).Ticks), DateTimeKind.Utc));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
waitUntil = _rateLimitStore.AddOrUpdate(key,
|
||||||
|
(s) => waitUntil,
|
||||||
|
(s, i) => new DateTime(Math.Max(waitUntil.Ticks, i.Add(interval).Ticks), DateTimeKind.Utc));
|
||||||
|
}
|
||||||
|
|
||||||
waitUntil -= interval;
|
waitUntil -= interval;
|
||||||
|
|
||||||
|
@ -129,6 +129,7 @@ private string DownloadFromWebUrl(RemoteMovie remoteMovie, string torrentUrl)
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var request = new HttpRequest(torrentUrl);
|
var request = new HttpRequest(torrentUrl);
|
||||||
|
request.RateLimitKey = remoteMovie?.Release?.IndexerId.ToString();
|
||||||
request.Headers.Accept = "application/x-bittorrent";
|
request.Headers.Accept = "application/x-bittorrent";
|
||||||
request.AllowAutoRedirect = false;
|
request.AllowAutoRedirect = false;
|
||||||
|
|
||||||
|
@ -44,7 +44,9 @@ public override string Download(RemoteMovie remoteMovie)
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
nzbData = _httpClient.Get(new HttpRequest(url)).ResponseData;
|
var request = new HttpRequest(url);
|
||||||
|
request.RateLimitKey = remoteMovie?.Release?.IndexerId.ToString();
|
||||||
|
nzbData = _httpClient.Get(request).ResponseData;
|
||||||
|
|
||||||
_logger.Debug("Downloaded nzb for movie '{0}' finished ({1} bytes from {2})", remoteMovie.Release.Title, nzbData.Length, url);
|
_logger.Debug("Downloaded nzb for movie '{0}' finished ({1} bytes from {2})", remoteMovie.Release.Title, nzbData.Length, url);
|
||||||
}
|
}
|
||||||
|
@ -301,6 +301,8 @@ protected virtual IndexerResponse FetchIndexerResponse(IndexerRequest request)
|
|||||||
request.HttpRequest.RateLimit = RateLimit;
|
request.HttpRequest.RateLimit = RateLimit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
request.HttpRequest.RateLimitKey = Definition.Id.ToString();
|
||||||
|
|
||||||
request.HttpRequest.AllowAutoRedirect = true;
|
request.HttpRequest.AllowAutoRedirect = true;
|
||||||
|
|
||||||
return new IndexerResponse(request, _httpClient.Execute(request.HttpRequest));
|
return new IndexerResponse(request, _httpClient.Execute(request.HttpRequest));
|
||||||
|
Loading…
Reference in New Issue
Block a user