From c5361cfc58f0792c3794c95054c34520724584cf Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Fri, 16 Oct 2020 12:07:55 -0400 Subject: [PATCH] [RateLimiter] rename Limit to RateLimit and add RateLimit::getLimit() --- .../AbstractRequestRateLimiter.php | 14 +++++----- .../RequestRateLimiterInterface.php | 4 +-- .../Component/RateLimiter/CompoundLimiter.php | 12 ++++----- .../MaxWaitDurationExceededException.php | 12 ++++----- .../Exception/RateLimitExceededException.php | 21 +++++++++------ .../RateLimiter/FixedWindowLimiter.php | 12 ++++----- .../RateLimiter/LimiterInterface.php | 2 +- .../Component/RateLimiter/NoLimiter.php | 6 ++--- .../RateLimiter/{Limit.php => RateLimit.php} | 11 ++++++-- .../Component/RateLimiter/Reservation.php | 10 +++---- .../RateLimiter/SlidingWindowLimiter.php | 6 ++--- .../Tests/FixedWindowLimiterTest.php | 22 +++++++++------- .../{LimitTest.php => RateLimitTest.php} | 14 +++++----- .../Tests/SlidingWindowLimiterTest.php | 16 +++++++----- .../Tests/TokenBucketLimiterTest.php | 26 ++++++++++--------- .../RateLimiter/TokenBucketLimiter.php | 14 +++++----- 16 files changed, 110 insertions(+), 92 deletions(-) rename src/Symfony/Component/RateLimiter/{Limit.php => RateLimit.php} (87%) rename src/Symfony/Component/RateLimiter/Tests/{LimitTest.php => RateLimitTest.php} (67%) diff --git a/src/Symfony/Component/HttpFoundation/RateLimiter/AbstractRequestRateLimiter.php b/src/Symfony/Component/HttpFoundation/RateLimiter/AbstractRequestRateLimiter.php index cf6d1e1bc3..f700ebcd86 100644 --- a/src/Symfony/Component/HttpFoundation/RateLimiter/AbstractRequestRateLimiter.php +++ b/src/Symfony/Component/HttpFoundation/RateLimiter/AbstractRequestRateLimiter.php @@ -12,9 +12,9 @@ namespace Symfony\Component\HttpFoundation\RateLimiter; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\RateLimiter\Limit; use Symfony\Component\RateLimiter\LimiterInterface; use Symfony\Component\RateLimiter\NoLimiter; +use Symfony\Component\RateLimiter\RateLimit; /** * An implementation of RequestRateLimiterInterface that @@ -26,23 +26,23 @@ use Symfony\Component\RateLimiter\NoLimiter; */ abstract class AbstractRequestRateLimiter implements RequestRateLimiterInterface { - public function consume(Request $request): Limit + public function consume(Request $request): RateLimit { $limiters = $this->getLimiters($request); if (0 === \count($limiters)) { $limiters = [new NoLimiter()]; } - $minimalLimit = null; + $minimalRateLimit = null; foreach ($limiters as $limiter) { - $limit = $limiter->consume(1); + $rateLimit = $limiter->consume(1); - if (null === $minimalLimit || $limit->getRemainingTokens() < $minimalLimit->getRemainingTokens()) { - $minimalLimit = $limit; + if (null === $minimalRateLimit || $rateLimit->getRemainingTokens() < $minimalRateLimit->getRemainingTokens()) { + $minimalRateLimit = $rateLimit; } } - return $minimalLimit; + return $minimalRateLimit; } public function reset(Request $request): void diff --git a/src/Symfony/Component/HttpFoundation/RateLimiter/RequestRateLimiterInterface.php b/src/Symfony/Component/HttpFoundation/RateLimiter/RequestRateLimiterInterface.php index d374277600..c7d31ba5db 100644 --- a/src/Symfony/Component/HttpFoundation/RateLimiter/RequestRateLimiterInterface.php +++ b/src/Symfony/Component/HttpFoundation/RateLimiter/RequestRateLimiterInterface.php @@ -12,7 +12,7 @@ namespace Symfony\Component\HttpFoundation\RateLimiter; use Symfony\Component\HttpFoundation\Request; -use Symfony\Component\RateLimiter\Limit; +use Symfony\Component\RateLimiter\RateLimit; /** * A special type of limiter that deals with requests. @@ -26,7 +26,7 @@ use Symfony\Component\RateLimiter\Limit; */ interface RequestRateLimiterInterface { - public function consume(Request $request): Limit; + public function consume(Request $request): RateLimit; public function reset(Request $request): void; } diff --git a/src/Symfony/Component/RateLimiter/CompoundLimiter.php b/src/Symfony/Component/RateLimiter/CompoundLimiter.php index 6722e0b436..2869409303 100644 --- a/src/Symfony/Component/RateLimiter/CompoundLimiter.php +++ b/src/Symfony/Component/RateLimiter/CompoundLimiter.php @@ -38,18 +38,18 @@ final class CompoundLimiter implements LimiterInterface throw new ReserveNotSupportedException(__CLASS__); } - public function consume(int $tokens = 1): Limit + public function consume(int $tokens = 1): RateLimit { - $minimalLimit = null; + $minimalRateLimit = null; foreach ($this->limiters as $limiter) { - $limit = $limiter->consume($tokens); + $rateLimit = $limiter->consume($tokens); - if (null === $minimalLimit || $limit->getRemainingTokens() < $minimalLimit->getRemainingTokens()) { - $minimalLimit = $limit; + if (null === $minimalRateLimit || $rateLimit->getRemainingTokens() < $minimalRateLimit->getRemainingTokens()) { + $minimalRateLimit = $rateLimit; } } - return $minimalLimit; + return $minimalRateLimit; } public function reset(): void diff --git a/src/Symfony/Component/RateLimiter/Exception/MaxWaitDurationExceededException.php b/src/Symfony/Component/RateLimiter/Exception/MaxWaitDurationExceededException.php index 025103f7a8..1eeec9de64 100644 --- a/src/Symfony/Component/RateLimiter/Exception/MaxWaitDurationExceededException.php +++ b/src/Symfony/Component/RateLimiter/Exception/MaxWaitDurationExceededException.php @@ -11,7 +11,7 @@ namespace Symfony\Component\RateLimiter\Exception; -use Symfony\Component\RateLimiter\Limit; +use Symfony\Component\RateLimiter\RateLimit; /** * @author Wouter de Jong @@ -20,17 +20,17 @@ use Symfony\Component\RateLimiter\Limit; */ class MaxWaitDurationExceededException extends \RuntimeException { - private $limit; + private $rateLimit; - public function __construct(string $message, Limit $limit, int $code = 0, ?\Throwable $previous = null) + public function __construct(string $message, RateLimit $rateLimit, int $code = 0, ?\Throwable $previous = null) { parent::__construct($message, $code, $previous); - $this->limit = $limit; + $this->rateLimit = $rateLimit; } - public function getLimit(): Limit + public function getRateLimit(): RateLimit { - return $this->limit; + return $this->rateLimit; } } diff --git a/src/Symfony/Component/RateLimiter/Exception/RateLimitExceededException.php b/src/Symfony/Component/RateLimiter/Exception/RateLimitExceededException.php index f96516e653..0cb10c750b 100644 --- a/src/Symfony/Component/RateLimiter/Exception/RateLimitExceededException.php +++ b/src/Symfony/Component/RateLimiter/Exception/RateLimitExceededException.php @@ -11,7 +11,7 @@ namespace Symfony\Component\RateLimiter\Exception; -use Symfony\Component\RateLimiter\Limit; +use Symfony\Component\RateLimiter\RateLimit; /** * @author Kevin Bond @@ -20,27 +20,32 @@ use Symfony\Component\RateLimiter\Limit; */ class RateLimitExceededException extends \RuntimeException { - private $limit; + private $rateLimit; - public function __construct(Limit $limit, $code = 0, \Throwable $previous = null) + public function __construct(RateLimit $rateLimit, $code = 0, \Throwable $previous = null) { parent::__construct('Rate Limit Exceeded', $code, $previous); - $this->limit = $limit; + $this->rateLimit = $rateLimit; } - public function getLimit(): Limit + public function getRateLimit(): RateLimit { - return $this->limit; + return $this->rateLimit; } public function getRetryAfter(): \DateTimeImmutable { - return $this->limit->getRetryAfter(); + return $this->rateLimit->getRetryAfter(); } public function getRemainingTokens(): int { - return $this->limit->getRemainingTokens(); + return $this->rateLimit->getRemainingTokens(); + } + + public function getLimit(): int + { + return $this->rateLimit->getLimit(); } } diff --git a/src/Symfony/Component/RateLimiter/FixedWindowLimiter.php b/src/Symfony/Component/RateLimiter/FixedWindowLimiter.php index 9164eb4ae5..bb0135d769 100644 --- a/src/Symfony/Component/RateLimiter/FixedWindowLimiter.php +++ b/src/Symfony/Component/RateLimiter/FixedWindowLimiter.php @@ -64,19 +64,19 @@ final class FixedWindowLimiter implements LimiterInterface if ($availableTokens >= $tokens) { $window->add($tokens); - $reservation = new Reservation($now, new Limit($window->getAvailableTokens($now), \DateTimeImmutable::createFromFormat('U', floor($now)), true)); + $reservation = new Reservation($now, new RateLimit($window->getAvailableTokens($now), \DateTimeImmutable::createFromFormat('U', floor($now)), true, $this->limit)); } else { $remainingTokens = $tokens - $availableTokens; $waitDuration = $window->calculateTimeForTokens($remainingTokens); if (null !== $maxTime && $waitDuration > $maxTime) { // process needs to wait longer than set interval - throw new MaxWaitDurationExceededException(sprintf('The rate limiter wait time ("%d" seconds) is longer than the provided maximum time ("%d" seconds).', $waitDuration, $maxTime), new Limit($window->getAvailableTokens($now), \DateTimeImmutable::createFromFormat('U', floor($now + $waitDuration)), false)); + throw new MaxWaitDurationExceededException(sprintf('The rate limiter wait time ("%d" seconds) is longer than the provided maximum time ("%d" seconds).', $waitDuration, $maxTime), new RateLimit($window->getAvailableTokens($now), \DateTimeImmutable::createFromFormat('U', floor($now + $waitDuration)), false, $this->limit)); } $window->add($tokens); - $reservation = new Reservation($now + $waitDuration, new Limit($window->getAvailableTokens($now), \DateTimeImmutable::createFromFormat('U', floor($now + $waitDuration)), false)); + $reservation = new Reservation($now + $waitDuration, new RateLimit($window->getAvailableTokens($now), \DateTimeImmutable::createFromFormat('U', floor($now + $waitDuration)), false, $this->limit)); } $this->storage->save($window); } finally { @@ -89,12 +89,12 @@ final class FixedWindowLimiter implements LimiterInterface /** * {@inheritdoc} */ - public function consume(int $tokens = 1): Limit + public function consume(int $tokens = 1): RateLimit { try { - return $this->reserve($tokens, 0)->getLimit(); + return $this->reserve($tokens, 0)->getRateLimit(); } catch (MaxWaitDurationExceededException $e) { - return $e->getLimit(); + return $e->getRateLimit(); } } diff --git a/src/Symfony/Component/RateLimiter/LimiterInterface.php b/src/Symfony/Component/RateLimiter/LimiterInterface.php index e04a7ea26b..f190f56354 100644 --- a/src/Symfony/Component/RateLimiter/LimiterInterface.php +++ b/src/Symfony/Component/RateLimiter/LimiterInterface.php @@ -43,7 +43,7 @@ interface LimiterInterface * * @param int $tokens the number of tokens required */ - public function consume(int $tokens = 1): Limit; + public function consume(int $tokens = 1): RateLimit; /** * Resets the limit. diff --git a/src/Symfony/Component/RateLimiter/NoLimiter.php b/src/Symfony/Component/RateLimiter/NoLimiter.php index 65f772a66e..13ccbf10b6 100644 --- a/src/Symfony/Component/RateLimiter/NoLimiter.php +++ b/src/Symfony/Component/RateLimiter/NoLimiter.php @@ -25,12 +25,12 @@ final class NoLimiter implements LimiterInterface { public function reserve(int $tokens = 1, ?float $maxTime = null): Reservation { - return new Reservation(time(), new Limit(\INF, new \DateTimeImmutable(), true)); + return new Reservation(time(), new RateLimit(\INF, new \DateTimeImmutable(), true, \INF)); } - public function consume(int $tokens = 1): Limit + public function consume(int $tokens = 1): RateLimit { - return new Limit(\INF, new \DateTimeImmutable(), true); + return new RateLimit(\INF, new \DateTimeImmutable(), true, \INF); } public function reset(): void diff --git a/src/Symfony/Component/RateLimiter/Limit.php b/src/Symfony/Component/RateLimiter/RateLimit.php similarity index 87% rename from src/Symfony/Component/RateLimiter/Limit.php rename to src/Symfony/Component/RateLimiter/RateLimit.php index fb59ceb127..64c706b6e6 100644 --- a/src/Symfony/Component/RateLimiter/Limit.php +++ b/src/Symfony/Component/RateLimiter/RateLimit.php @@ -18,17 +18,19 @@ use Symfony\Component\RateLimiter\Exception\RateLimitExceededException; * * @experimental in 5.2 */ -class Limit +class RateLimit { private $availableTokens; private $retryAfter; private $accepted; + private $limit; - public function __construct(int $availableTokens, \DateTimeImmutable $retryAfter, bool $accepted) + public function __construct(int $availableTokens, \DateTimeImmutable $retryAfter, bool $accepted, int $limit) { $this->availableTokens = $availableTokens; $this->retryAfter = $retryAfter; $this->accepted = $accepted; + $this->limit = $limit; } public function isAccepted(): bool @@ -58,6 +60,11 @@ class Limit return $this->availableTokens; } + public function getLimit(): int + { + return $this->limit; + } + public function wait(): void { sleep(($this->retryAfter->getTimestamp() - time()) * 1e6); diff --git a/src/Symfony/Component/RateLimiter/Reservation.php b/src/Symfony/Component/RateLimiter/Reservation.php index 26a1d1750d..4ea54ce5a8 100644 --- a/src/Symfony/Component/RateLimiter/Reservation.php +++ b/src/Symfony/Component/RateLimiter/Reservation.php @@ -19,15 +19,15 @@ namespace Symfony\Component\RateLimiter; final class Reservation { private $timeToAct; - private $limit; + private $rateLimit; /** * @param float $timeToAct Unix timestamp in seconds when this reservation should act */ - public function __construct(float $timeToAct, Limit $limit) + public function __construct(float $timeToAct, RateLimit $rateLimit) { $this->timeToAct = $timeToAct; - $this->limit = $limit; + $this->rateLimit = $rateLimit; } public function getTimeToAct(): float @@ -40,9 +40,9 @@ final class Reservation return max(0, (-microtime(true)) + $this->timeToAct); } - public function getLimit(): Limit + public function getRateLimit(): RateLimit { - return $this->limit; + return $this->rateLimit; } public function wait(): void diff --git a/src/Symfony/Component/RateLimiter/SlidingWindowLimiter.php b/src/Symfony/Component/RateLimiter/SlidingWindowLimiter.php index dcdf619843..4d89e89615 100644 --- a/src/Symfony/Component/RateLimiter/SlidingWindowLimiter.php +++ b/src/Symfony/Component/RateLimiter/SlidingWindowLimiter.php @@ -76,7 +76,7 @@ final class SlidingWindowLimiter implements LimiterInterface /** * {@inheritdoc} */ - public function consume(int $tokens = 1): Limit + public function consume(int $tokens = 1): RateLimit { $this->lock->acquire(true); @@ -91,13 +91,13 @@ final class SlidingWindowLimiter implements LimiterInterface $hitCount = $window->getHitCount(); $availableTokens = $this->getAvailableTokens($hitCount); if ($availableTokens < $tokens) { - return new Limit($availableTokens, $window->getRetryAfter(), false); + return new RateLimit($availableTokens, $window->getRetryAfter(), false, $this->limit); } $window->add($tokens); $this->storage->save($window); - return new Limit($this->getAvailableTokens($window->getHitCount()), $window->getRetryAfter(), true); + return new RateLimit($this->getAvailableTokens($window->getHitCount()), $window->getRetryAfter(), true, $this->limit); } finally { $this->lock->release(); } diff --git a/src/Symfony/Component/RateLimiter/Tests/FixedWindowLimiterTest.php b/src/Symfony/Component/RateLimiter/Tests/FixedWindowLimiterTest.php index a6f436616f..8ae6dcc875 100644 --- a/src/Symfony/Component/RateLimiter/Tests/FixedWindowLimiterTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/FixedWindowLimiterTest.php @@ -41,10 +41,12 @@ class FixedWindowLimiterTest extends TestCase sleep(5); } - $limit = $limiter->consume(); - $this->assertTrue($limit->isAccepted()); - $limit = $limiter->consume(); - $this->assertFalse($limit->isAccepted()); + $rateLimit = $limiter->consume(); + $this->assertSame(10, $rateLimit->getLimit()); + $this->assertTrue($rateLimit->isAccepted()); + $rateLimit = $limiter->consume(); + $this->assertFalse($rateLimit->isAccepted()); + $this->assertSame(10, $rateLimit->getLimit()); } public function testConsumeOutsideInterval() @@ -58,18 +60,18 @@ class FixedWindowLimiterTest extends TestCase $limiter->consume(9); // ...try bursting again at the start of the next window sleep(10); - $limit = $limiter->consume(10); - $this->assertEquals(0, $limit->getRemainingTokens()); - $this->assertTrue($limit->isAccepted()); + $rateLimit = $limiter->consume(10); + $this->assertEquals(0, $rateLimit->getRemainingTokens()); + $this->assertTrue($rateLimit->isAccepted()); } public function testWrongWindowFromCache() { $this->storage->save(new DummyWindow()); $limiter = $this->createLimiter(); - $limit = $limiter->consume(); - $this->assertTrue($limit->isAccepted()); - $this->assertEquals(9, $limit->getRemainingTokens()); + $rateLimit = $limiter->consume(); + $this->assertTrue($rateLimit->isAccepted()); + $this->assertEquals(9, $rateLimit->getRemainingTokens()); } private function createLimiter(): FixedWindowLimiter diff --git a/src/Symfony/Component/RateLimiter/Tests/LimitTest.php b/src/Symfony/Component/RateLimiter/Tests/RateLimitTest.php similarity index 67% rename from src/Symfony/Component/RateLimiter/Tests/LimitTest.php rename to src/Symfony/Component/RateLimiter/Tests/RateLimitTest.php index a986581114..c62eda36f4 100644 --- a/src/Symfony/Component/RateLimiter/Tests/LimitTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/RateLimitTest.php @@ -13,25 +13,25 @@ namespace Symfony\Component\RateLimiter\Tests; use PHPUnit\Framework\TestCase; use Symfony\Component\RateLimiter\Exception\RateLimitExceededException; -use Symfony\Component\RateLimiter\Limit; +use Symfony\Component\RateLimiter\RateLimit; -class LimitTest extends TestCase +class RateLimitTest extends TestCase { public function testEnsureAcceptedDoesNotThrowExceptionIfAccepted() { - $limit = new Limit(10, new \DateTimeImmutable(), true); + $rateLimit = new RateLimit(10, new \DateTimeImmutable(), true, 10); - $this->assertSame($limit, $limit->ensureAccepted()); + $this->assertSame($rateLimit, $rateLimit->ensureAccepted()); } public function testEnsureAcceptedThrowsRateLimitExceptionIfNotAccepted() { - $limit = new Limit(10, $retryAfter = new \DateTimeImmutable(), false); + $rateLimit = new RateLimit(10, $retryAfter = new \DateTimeImmutable(), false, 10); try { - $limit->ensureAccepted(); + $rateLimit->ensureAccepted(); } catch (RateLimitExceededException $exception) { - $this->assertSame($limit, $exception->getLimit()); + $this->assertSame($rateLimit, $exception->getRateLimit()); $this->assertSame(10, $exception->getRemainingTokens()); $this->assertSame($retryAfter, $exception->getRetryAfter()); diff --git a/src/Symfony/Component/RateLimiter/Tests/SlidingWindowLimiterTest.php b/src/Symfony/Component/RateLimiter/Tests/SlidingWindowLimiterTest.php index 341f216c29..07146c765d 100644 --- a/src/Symfony/Component/RateLimiter/Tests/SlidingWindowLimiterTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/SlidingWindowLimiterTest.php @@ -38,17 +38,19 @@ class SlidingWindowLimiterTest extends TestCase $limiter->consume(8); sleep(15); - $limit = $limiter->consume(); - $this->assertTrue($limit->isAccepted()); + $rateLimit = $limiter->consume(); + $this->assertTrue($rateLimit->isAccepted()); + $this->assertSame(10, $rateLimit->getLimit()); // We are 25% into the new window - $limit = $limiter->consume(5); - $this->assertFalse($limit->isAccepted()); - $this->assertEquals(3, $limit->getRemainingTokens()); + $rateLimit = $limiter->consume(5); + $this->assertFalse($rateLimit->isAccepted()); + $this->assertEquals(3, $rateLimit->getRemainingTokens()); sleep(13); - $limit = $limiter->consume(10); - $this->assertTrue($limit->isAccepted()); + $rateLimit = $limiter->consume(10); + $this->assertTrue($rateLimit->isAccepted()); + $this->assertSame(10, $rateLimit->getLimit()); } public function testReserve() diff --git a/src/Symfony/Component/RateLimiter/Tests/TokenBucketLimiterTest.php b/src/Symfony/Component/RateLimiter/Tests/TokenBucketLimiterTest.php index 714ff15063..b5b83649e2 100644 --- a/src/Symfony/Component/RateLimiter/Tests/TokenBucketLimiterTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/TokenBucketLimiterTest.php @@ -74,26 +74,28 @@ class TokenBucketLimiterTest extends TestCase $limiter = $this->createLimiter(10, $rate); // enough free tokens - $limit = $limiter->consume(5); - $this->assertTrue($limit->isAccepted()); - $this->assertEquals(5, $limit->getRemainingTokens()); - $this->assertEqualsWithDelta(time(), $limit->getRetryAfter()->getTimestamp(), 1); + $rateLimit = $limiter->consume(5); + $this->assertTrue($rateLimit->isAccepted()); + $this->assertEquals(5, $rateLimit->getRemainingTokens()); + $this->assertEqualsWithDelta(time(), $rateLimit->getRetryAfter()->getTimestamp(), 1); + $this->assertSame(10, $rateLimit->getLimit()); // there are only 5 available free tokens left now - $limit = $limiter->consume(10); - $this->assertEquals(5, $limit->getRemainingTokens()); + $rateLimit = $limiter->consume(10); + $this->assertEquals(5, $rateLimit->getRemainingTokens()); - $limit = $limiter->consume(5); - $this->assertEquals(0, $limit->getRemainingTokens()); - $this->assertEqualsWithDelta(time(), $limit->getRetryAfter()->getTimestamp(), 1); + $rateLimit = $limiter->consume(5); + $this->assertEquals(0, $rateLimit->getRemainingTokens()); + $this->assertEqualsWithDelta(time(), $rateLimit->getRetryAfter()->getTimestamp(), 1); + $this->assertSame(10, $rateLimit->getLimit()); } public function testWrongWindowFromCache() { $this->storage->save(new DummyWindow()); $limiter = $this->createLimiter(); - $limit = $limiter->consume(); - $this->assertTrue($limit->isAccepted()); - $this->assertEquals(9, $limit->getRemainingTokens()); + $rateLimit = $limiter->consume(); + $this->assertTrue($rateLimit->isAccepted()); + $this->assertEquals(9, $rateLimit->getRemainingTokens()); } private function createLimiter($initialTokens = 10, Rate $rate = null) diff --git a/src/Symfony/Component/RateLimiter/TokenBucketLimiter.php b/src/Symfony/Component/RateLimiter/TokenBucketLimiter.php index b8997ac7e0..64b3046ec3 100644 --- a/src/Symfony/Component/RateLimiter/TokenBucketLimiter.php +++ b/src/Symfony/Component/RateLimiter/TokenBucketLimiter.php @@ -74,16 +74,16 @@ final class TokenBucketLimiter implements LimiterInterface $bucket->setTokens($availableTokens - $tokens); $bucket->setTimer($now); - $reservation = new Reservation($now, new Limit($bucket->getAvailableTokens($now), \DateTimeImmutable::createFromFormat('U', floor($now)), true)); + $reservation = new Reservation($now, new RateLimit($bucket->getAvailableTokens($now), \DateTimeImmutable::createFromFormat('U', floor($now)), true, $this->maxBurst)); } else { $remainingTokens = $tokens - $availableTokens; $waitDuration = $this->rate->calculateTimeForTokens($remainingTokens); if (null !== $maxTime && $waitDuration > $maxTime) { // process needs to wait longer than set interval - $limit = new Limit($availableTokens, \DateTimeImmutable::createFromFormat('U', floor($now + $waitDuration)), false); + $rateLimit = new RateLimit($availableTokens, \DateTimeImmutable::createFromFormat('U', floor($now + $waitDuration)), false, $this->maxBurst); - throw new MaxWaitDurationExceededException(sprintf('The rate limiter wait time ("%d" seconds) is longer than the provided maximum time ("%d" seconds).', $waitDuration, $maxTime), $limit); + throw new MaxWaitDurationExceededException(sprintf('The rate limiter wait time ("%d" seconds) is longer than the provided maximum time ("%d" seconds).', $waitDuration, $maxTime), $rateLimit); } // at $now + $waitDuration all tokens will be reserved for this process, @@ -91,7 +91,7 @@ final class TokenBucketLimiter implements LimiterInterface $bucket->setTokens(0); $bucket->setTimer($now + $waitDuration); - $reservation = new Reservation($bucket->getTimer(), new Limit(0, \DateTimeImmutable::createFromFormat('U', floor($now + $waitDuration)), false)); + $reservation = new Reservation($bucket->getTimer(), new RateLimit(0, \DateTimeImmutable::createFromFormat('U', floor($now + $waitDuration)), false, $this->maxBurst)); } $this->storage->save($bucket); @@ -105,12 +105,12 @@ final class TokenBucketLimiter implements LimiterInterface /** * {@inheritdoc} */ - public function consume(int $tokens = 1): Limit + public function consume(int $tokens = 1): RateLimit { try { - return $this->reserve($tokens, 0)->getLimit(); + return $this->reserve($tokens, 0)->getRateLimit(); } catch (MaxWaitDurationExceededException $e) { - return $e->getLimit(); + return $e->getRateLimit(); } } }