Rate Limiter
Available versions:
Installation
composer require aeon-php/rate-limiter
Description
RateLimiter components makes possible to limit frequency of operations execution.
Following example shows how to use Leaky Bucket algorithm
with Rate Limiter. This configuration will let 5 immediate executions with restore rate 1 execution every minute.
It's recommended to replace Symfony\Component\Cache\Adapter\ArrayAdapter
(in memory) adapter used by PSRCacheStorage
with a more permanent storage, like for example Redis.
<?php
$calendar = GregorianCalendar::UTC();
$rateLimiter = new RateLimiter(
new LeakyBucketAlgorithm(
$calendar,
$bucketSize = 5,
$leakSize = 1,
$leakTime = TimeUnit::minute()
),
new PSRCacheStorage(
new ArrayAdapter(),
$calendar
)
);
$rateLimiter->hit('operation.id');
$rateLimiter->hit('operation.id');
$rateLimiter->hit('operation.id');
$rateLimiter->hit('operation.id');
$rateLimiter->hit('operation.id');
try {
$rateLimiter->hit('operation.id');
} catch (RateLimitException $exception) {
echo "Rate limit exceeded, please wait {$exception->retryIn()->inSecondsPrecise()} seconds";
}
// this will put process into sleep for next ~59 seconds
$rateLimiter->throttle('operation.id', SystemProcess::current());
Rate Limiter implements following limiting algorithms:
Rate Limiter implements following types of storage
- MemoryStorage
- PSRCacheStorage
It's worth to mention that PSRCacheStorage works perfectly fine with any caching library that implements PSR-6: Caching Interface. Most of available PSR-6 implementations can be found at packagist.
RateLimiter API is pretty much self-explanatory
<?php
namespace Aeon\RateLimiter;
final class RateLimiter
{
/**
* Record next hit, throws an extension where there are no available hits left according to the selected algorithm.
*
* @throws \Aeon\RateLimiter\Exception\RateLimitException
*/
public function hit(string $id) : void;
/**
* Estimate time required to the next hit. If current capacity is greater than 0, time will be 0.
*/
public function estimate(string $id) : TimeUnit;
/**
* Returns current capacity according to the selected algorithm, when there are no available hits left, it will return 0.
* Use RateLimiter::estimate method to find out when next hit will be possible.
*/
public function capacity(string $id) : int;
/**
* Initial available capacity before registering any hits or when all hits time out.
*/
public function capacityInitial() : int;
/**
* Time required to fully reset to the total capacity.
*/
public function resetIn(string $id) : TimeUnit;
/**
* Try to record next hit, in case of rate limit exception take the cooldown time and sleep current process.
*/
public function throttle(string $id, Process $process) : void;
}
RateLimitException
does not only tell you that the execution is forbidden, it also
says how long you should wait.
<?php
public function throttle(string $id, Process $process) : void
{
try {
$this->algorithm->hit($id, $this->storage);
} catch (RateLimitException $rateLimitException) {
$process->sleep($rateLimitException->cooldown());
$this->algorithm->hit($id, $this->storage);
}
}