8000 [RateLimiter] TokenBucket strategy refills tokens incorrectly · Issue #47676 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content
[RateLimiter] TokenBucket strategy refills tokens incorrectly #47676
Closed
@taxp

Description

@taxp

Symfony version(s) affected

5.2., 6.

Description

TokenBucket strategy for RateLimiter tries to refill tokens by every call of \Symfony\Component\RateLimiter\Policy\TokenBucketLimiter::reserve. Amount of refilled tokens calculated in \Symfony\Component\RateLimiter\Policy\Rate::calculateNewTokensDuringInterval. The problem is that refill actually executes no more than once per second, even if RPS is high as well as refill rate.
So some of requests in the end of a second may be skiped being unable to reserve tokens which should be restored already.

How to reproduce

$limiter = (new Symfony\Component\RateLimiter\RateLimiterFactory(
    [
        'id' => 'id',
        'policy' => 'token_bucket',
        'limit' => 10,
        'rate' => [
            'interval' => '1 second',
            'amount' => 2,
        ],
    ],
    new Symfony\Component\RateLimiter\Storage\InMemoryStorage()
))->create();

$res = $limiter->consume(1);
var_dump($res->getRemainingTokens());  //9 tokens last
usleep(600000);  //with rate "1 token/0.5 second" it should be 10 tokens
$res = $limiter->consume(10);
var_dump($res->isAccepted()); //false but should be true

Possible Solution

Calculate tokens to restore everytime, not just every second.

\Symfony\Component\RateLimiter\Policy\Rate::calculateNewTokensDuringInterval

public function calculateNewTokensDuringInterval(float $duration): int
{
    return floor($this->refillAmount * $duration / TimeUtil::dateIntervalToSeconds($this->refillTime));     
}

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0