2013-06-05 3 views
3

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

Tos.Snd Last.fm утверждает, что я не могу сделать более 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?

ответ

2

Это, на мой взгляд, довольно хорошо. Кроме того, в этом коде есть ошибка. Это потому, что, если каждый запрос выполняется более секунды после друг друга? Он никогда не войдет внутрь этого блока if. Таким образом, какой-то memory leak, потому что _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); 
} 
+0

Да, я заметил, что сразу после публикации ... Спасибо! :) – jjdev80

1

Я написал библиотеку 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 package.