Final Class Yiisoft\Yii\RateLimiter\Counter
| Inheritance | Yiisoft\Yii\RateLimiter\Counter |
|---|---|
| Implements | Yiisoft\Yii\RateLimiter\CounterInterface |
Counter implements generic cell rate limit algorithm (GCRA) that ensures that after reaching the limit further increments are distributed equally.
Public Methods
| Method | Description | Defined By |
|---|---|---|
| __construct() | Yiisoft\Yii\RateLimiter\Counter | |
| hit() | Determines when the next hit won't be limited. Should be called on each request. | Yiisoft\Yii\RateLimiter\Counter |
Constants
| Constant | Value | Description | Defined By |
|---|---|---|---|
| DEFAULT_MAX_CAS_ATTEMPTS | 10 | Yiisoft\Yii\RateLimiter\Counter | |
| DEFAULT_TTL | 86400 | Yiisoft\Yii\RateLimiter\Counter | |
| ID_PREFIX | 'rate-limiter-' | Yiisoft\Yii\RateLimiter\Counter | |
| MILLISECONDS_PER_SECOND | 1000 | Yiisoft\Yii\RateLimiter\Counter |
Method Details
| public mixed __construct ( Yiisoft\Yii\RateLimiter\Storage\StorageInterface $storage, integer $limit, integer $periodInSeconds, integer $storageTtlInSeconds = self::DEFAULT_TTL, string $storagePrefix = self::ID_PREFIX, Yiisoft\Yii\RateLimiter\Time\TimerInterface|null $timer = null, integer $maxCasAttempts = self::DEFAULT_MAX_CAS_ATTEMPTS ) | ||
| $storage | Yiisoft\Yii\RateLimiter\Storage\StorageInterface |
Storage to use for counter values. |
| $limit | integer |
Maximum number of increments that could be performed before increments are limited. |
| $periodInSeconds | integer |
Period to apply limit to. |
| $storageTtlInSeconds | integer |
Storage TTL. Should be higher than |
| $storagePrefix | string |
Storage prefix. |
| $timer | Yiisoft\Yii\RateLimiter\Time\TimerInterface|null |
Timer instance to get current time from. |
| $maxCasAttempts | integer |
Maximum number of times to retry saveIfNotExists/saveCompareAndSwap operations before returning an error. |
public function __construct(
private StorageInterface $storage,
private int $limit,
int $periodInSeconds,
private int $storageTtlInSeconds = self::DEFAULT_TTL,
private string $storagePrefix = self::ID_PREFIX,
TimerInterface|null $timer = null,
private int $maxCasAttempts = self::DEFAULT_MAX_CAS_ATTEMPTS,
) {
if ($limit < 1) {
throw new InvalidArgumentException('The limit must be a positive value.');
}
if ($periodInSeconds < 1) {
throw new InvalidArgumentException('The period must be a positive value.');
}
$this->periodInMilliseconds = $periodInSeconds * self::MILLISECONDS_PER_SECOND;
$this->timer = $timer ?: new MicrotimeTimer();
$this->incrementIntervalInMilliseconds = $this->periodInMilliseconds / $this->limit;
}
Determines when the next hit won't be limited. Should be called on each request.
| public Yiisoft\Yii\RateLimiter\CounterState hit ( string $id ) | ||
| $id | string |
Counter ID. Counters with distinct IDs do not affect each other. For example, using a current user ID will limit for the current user and using IP will limit by IP. |
| return | Yiisoft\Yii\RateLimiter\CounterState |
Information about when the next hit won't be limited. |
|---|---|---|
public function hit(string $id): CounterState
{
$attempts = 0;
$isFailStoreUpdatedData = false;
do {
// Last increment time.
// In GCRA it's known as arrival time.
$lastIncrementTimeInMilliseconds = $this->timer->nowInMilliseconds();
$lastStoredTheoreticalNextIncrementTime = $this->getLastStoredTheoreticalNextIncrementTime($id);
$theoreticalNextIncrementTime = $this->calculateTheoreticalNextIncrementTime(
$lastIncrementTimeInMilliseconds,
$lastStoredTheoreticalNextIncrementTime
);
$remaining = $this->calculateRemaining($lastIncrementTimeInMilliseconds, $theoreticalNextIncrementTime);
$resetAfter = $this->calculateResetAfter($theoreticalNextIncrementTime);
if ($remaining === 0) {
break;
}
$isStored = $this->storeTheoreticalNextIncrementTime(
$id,
$theoreticalNextIncrementTime,
$lastStoredTheoreticalNextIncrementTime
);
if ($isStored) {
break;
}
$attempts++;
if ($attempts >= $this->maxCasAttempts) {
$isFailStoreUpdatedData = true;
break;
}
} while (true);
return new CounterState($this->limit, $remaining, $resetAfter, $isFailStoreUpdatedData);
}
Signup or Login in order to comment.