davedevelopment / stiphle

A simple PHP library for throttling or rate limiting

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Not sure if the getEstimate() gives out correct waiting time

NinoSkopac opened this issue · comments

commented

I've done a couple of tests:

  1. If I limit the requests to 1 per minute: I do the request, and then I cannot do it for the next 60 seconds. Good.
  2. If I limit the requests to 2 per minute: I do the requests, and then I have to wait 30 seconds. Is this how it should be?

Let's look at it from a end-user POV, not programming: if I make 2 requests one after another, and the rate limit is 2 per 60 seconds, should I wait 30 seconds or 60 seconds in order to do a 3rd one? I'd say 60.

Code excerpts from my internal user class:

public const Rate_Limits = [ // [$limit, $time] where $time is in seconds
    [2, 1],
    [2, 60], // testing value of 2 for dev purposes, will be something like 10 in production
    [150, 3600]
];

// from constructor; classes are aliased
self::$LeakyBucket = new LeakyBucket;
self::$LeakyBucket->setStorage(new StiphleApcu);

/**
 * If the returned value is null, it means there's no throttling needed for this request.
 *
 * @return array|null
 */
public static function getRateLimitRemaining(): ?array
{
    $uid = self::getInternalUserIdentifier();

    foreach (self::Rate_Limits as [$limit, $seconds]) {
        $estimate = self::$LeakyBucket->getEstimate($uid, $limit, $seconds * 1000);

        if ($estimate === 0)
            self::$LeakyBucket->throttle($uid, $limit, $seconds * 1000);
        else
            return [
                'request_limit' => $limit,
                'estimated_wait_miliseconds' => $estimate,
                'estimated_wait_human_readable' => Parse::secondsToHoursMinutesSeconds((int) round($estimate / 1000)),
                'timeframe_seconds' => $seconds,
                'timeframe_seconds_human_readable' => Parse::secondsToHoursMinutesSeconds($seconds),
            ];
    }

    return null;
}

php 7.1.1, ubuntu 16

The Leaky Bucket algorithm is a little like a rolling minute. It only throttles when the bucket is full. So, initially, you can burst to fill the bucket, but after that, it's more like the timings you would expect.

If you want something that might be a little easier for your users to understand, you can use the TimeWindow throttle, which works based on you can do 2 requests between 00:00:00 and 00:00:01, 2 requests between 00:00:01 and 00:00:02 etc.