Ограничитель скорости API

87
10

Я написал ограничитель скорости API для использования с API Last.fm.


Last.fm Tos утверждает, что я не могу сделать более 5 запросов на исходящий IP-адрес в секунду, усредненный за 5-минутный период.


Вот класс, который я написал:


public class RateLimiter
{
private static readonly List<DateTime> _requests = new List<DateTime>();

private const double _perMillisecond = 1000.1;
private const int _rateLimit = 5;
private const int _rateLimitCooldownMs = 500;

public static void CheckLimiter()
{
_requests.Add(DateTime.Now);

var requestsDuringRateLimit = _requests.Where(w => (DateTime.Now - w).TotalMilliseconds < _perMillisecond).ToArray();

if (requestsDuringRateLimit.Count() >= _rateLimit)
{
Thread.Sleep(_rateLimitCooldownMs);
_requests.Clear();
Console.Clear();
}
}
}


Метод CheckLimiter вызывается до запуска HttpWebRequest, это хороший способ ограничить запросы API?

спросил(а) 2021-01-07T20:58:04+03:00 3 месяца назад
1
Решение
75

Это, на мой взгляд, неплохо. Кроме того, в этом коде есть ошибка. Это потому, что, если каждый запрос выполняется более секунды после друг друга? Он никогда не войдет внутрь этого блока if. Таким образом, некоторая утечка памяти, поскольку _requests будет увеличиваться с течением времени и, возможно, никогда не будет очищена, если мой сценарий выше всегда.


Пример:


for (int i = 0; i < 100; i++)
{
RateLimiter.CheckLimiter();
Thread.Sleep(2000);
}

Что вы можете сделать, так это удалить записи в _requests, которые превышают правило 1 секунды, например добавление этой строки в конце вашего метода.


if (_requests.Count != 0)
{
//remove irrelevant/expired entries
_requests.RemoveAll(date => (DateTime.Now - date).TotalMilliseconds >= _perMillisecond);
}

ответил(а) 2021-01-07T20:58:04+03:00 3 месяца назад
63

Я написал библиотеку RateLimiter, чтобы справиться с такими ограничениями. Основным преимуществом нашего предлагаемого решения является то, что он является асинхронным и отменяется. Другая особенность заключается в том, что вы можете создавать ограничения для создания сложного ограничения.


Пример:


var timeconstraint = TimeLimiter.GetFromMaxCountByInterval(5, TimeSpan.FromSeconds(1));

for(int i=0; i<1000; i++)
{
await timeconstraint.Perform(ConsoleIt);
}

....
private Task ConsoleIt()
{
Trace.WriteLine(string.Format("{0:MM/dd/yyy HH:mm:ss.fff}", DateTime.Now));
return Task.FromResult(0);
}

Составлено:


var constraint = new CountByIntervalAwaitableConstraint(5, TimeSpan.FromSeconds(1));

//Create second constraint: one time each 100 ms
var constraint2 = new CountByIntervalAwaitableConstraint(1, TimeSpan.FromMilliseconds(100));

//Compose the two constraints
var timeconstraint = TimeLimiter.Compose(constraint, constraint2);

//Use it
for(int i=0; i<1000; i++)
{
await timeconstraint.Perform(ConsoleIt);
}


Он также доступен как пакет nuget.

ответил(а) 2021-01-07T20:58:04+03:00 3 месяца назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема