Search code examples
c#weblast.fmsystem.net.httpwebrequest

An API rate limiter


I wrote an API rate limiter to use with Last.fm's API.

Last.fm's Tos states that I cannot make more than 5 requests per originating IP address per second, averaged over a 5 minute period.

Here is the class I wrote:

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();
        }
    }
}

The CheckLimiter method is called before the HttpWebRequest is initiated, is this a good way to limit API requests?


Solution

  • This is quite fine in my opinion. Except that, there is a bug in this code. This is because what if each request is done more than a second after one another? It will never go inside that if block. Thus, some kind of memory leak because the _requests will grow larger over time and possibly never be cleared if my scenario above always happens.

    Example:

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

    What you can do is to remove entries in your _requests that are exceeding the 1 second rule like adding this line at the end of your method.

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