Rate limiting
, (*1)
A rate limiting can be used to limit the rate at which physical or logical resources are accessed, e.g. to protect them from intentional or unintentional overuse., (*2)
Restricting usage
Imagine you don't want to run more than two tasks per second:, (*3)
use util\invoke\RateLimiting;
$rateLimiter= new RateLimiting(2);
foreach ($tasks as $task) {
$rateLimiter->acquire(); // will wait if necessary
$task->run();
}
Restricting bandwidth
You can implement bandwidth throttling by acquiring a permit for each byte:, (*4)
use util\invoke\{RateLimiting, Rate, Per};
$rateLimiter= new RateLimiting(new Rate(1000000, Per::$MINUTE));
while ($bytes= $source->read()) {
$rateLimiter->acquire(strlen($bytes));
$target->write($bytes);
}
Rate-limiting users
Implement a filter like the following:, (*5)
use web\{Filter, Error};
use util\invoke\{RateLimiting, Rate, Per};
class RateLimitingFilter implements Filter {
private $rates, $rate, $timeout;
public function __construct(KeyValueStorage $rates) {
$this->rates= $rates;
$this->rate= new Rate(5000, Per::$HOUR);
$this->timeout= 0.2;
}
public function filter($request, $response, $invocation) {
$remote= $request->header('Remote-Addr');
$limits= $this->rates->get($remote) ?: new RateLimiting($this->rate);
$permitted= $limits->tryAcquiring(1, $this->timeout);
$this->rates->put($remote, $limits);
$response->header('X-RateLimit-Limit', $limits->rate()->value());
$response->header('X-RateLimit-Remaining', $limits->remaining());
$response->header('X-RateLimit-Reset', $limits->resetTime());
if (!$permitted) {
throw new Error(429, 'Rate limit exceeded');
}
return $invocation->proceed($request, $response);
}
}
Further reading