I use a variety of 3rd party web APIs, and many of them enforce rate limiting. It would be very useful to have a fairly generic PHP library that I could rate limit my calls with. I can think of a few ways to do it, perhaps by putting calls into a queue with a timestamp of when the call can be made, but I was hoping to avoid reinventing the wheel if someone else has already done this well.
I realize this is an old thread but thought I'd post my solution since it was based on something else I found on SE. I looked for a while for an answer myself but had trouble finding something good. It's based on the Python solution discussed here, but I've added support for variable-sized requests and turned it into a function generator using PHP closures.
function ratelimiter($rate = 5, $per = 8) {
$last_check = microtime(True);
$allowance = $rate;
return function ($consumed = 1) use (
&$last_check,
&$allowance,
$rate,
$per
) {
$current = microtime(True);
$time_passed = $current - $last_check;
$last_check = $current;
$allowance += $time_passed * ($rate / $per);
if ($allowance > $rate)
$allowance = $rate;
if ($allowance < $consumed) {
$duration = ($consumed - $allowance) * ($per / $rate);
$last_check += $duration;
usleep($duration * 1000000);
$allowance = 0;
}
else
$allowance -= $consumed;
return;
};
}
It can be used to limit just about anything. Here's a stupid example that limits a simple statement at the default five "requests" per eight seconds:
$ratelimit = ratelimiter();
while (True) {
$ratelimit();
echo "foo".PHP_EOL;
}
Here's how I'm using it to limit batched requests against the Facebook Graph API at 600 requests per 600 seconds based on the size of the batch:
$ratelimit = ratelimiter(600, 600);
while (..) {
..
$ratelimit(count($requests));
$response = (new FacebookRequest(
$session, 'POST', '/', ['batch' => json_encode($requests)]
))->execute();
foreach ($response->..) {
..
}
}
Hope this helps someone!
You can do rate limiting with the token bucket algorithm. I implemented that for you in PHP: bandwidth-throttle/token-bucket :
use bandwidthThrottle\tokenBucket\Rate;
use bandwidthThrottle\tokenBucket\TokenBucket;
use bandwidthThrottle\tokenBucket\storage\FileStorage;
$storage = new FileStorage(__DIR__ . "/api.bucket");
$rate = new Rate(10, Rate::SECOND);
$bucket = new TokenBucket(10, $rate, $storage);
$bucket->bootstrap(10);
if (!$bucket->consume(1, $seconds)) {
http_response_code(429);
header(sprintf("Retry-After: %d", floor($seconds)));
exit();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With