From 62e3e5cda956655c1984a8663d422a59b3def5b4 Mon Sep 17 00:00:00 2001 From: SanderSander Date: Wed, 1 Nov 2023 22:35:08 +0100 Subject: [PATCH 1/2] Fix reservations outside the second fixed window --- .../Component/RateLimiter/Policy/Window.php | 3 ++- .../Tests/Policy/FixedWindowLimiterTest.php | 17 +++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/RateLimiter/Policy/Window.php b/src/Symfony/Component/RateLimiter/Policy/Window.php index 42d00de913c0e..42d65f6483a07 100644 --- a/src/Symfony/Component/RateLimiter/Policy/Window.php +++ b/src/Symfony/Component/RateLimiter/Policy/Window.php @@ -77,7 +77,8 @@ public function calculateTimeForTokens(int $tokens, float $now): int return 0; } - return (int) ceil($this->timer + $this->intervalInSeconds - $now); + $inWindow = ceil($this->hitCount / $this->maxSize); + return (int) ceil($this->timer + ($this->intervalInSeconds * $inWindow) - $now); } public function __serialize(): array diff --git a/src/Symfony/Component/RateLimiter/Tests/Policy/FixedWindowLimiterTest.php b/src/Symfony/Component/RateLimiter/Tests/Policy/FixedWindowLimiterTest.php index 3e422fbec55b0..fa787c8a6fc32 100644 --- a/src/Symfony/Component/RateLimiter/Tests/Policy/FixedWindowLimiterTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/Policy/FixedWindowLimiterTest.php @@ -76,6 +76,23 @@ public function testConsumeOutsideInterval(string $dateIntervalString) $this->assertTrue($rateLimit->isAccepted()); } + public function testReserveOutsideWindow() + { + $limiter = $this->createLimiter(); + + // initial reserve + $limiter->reserve(10); + + // Reserve the first window and the second window + $firstReservation = $limiter->reserve(10); + $secondReservation = $limiter->reserve(10); + + $this->assertFalse($firstReservation->getRateLimit()->isAccepted()); + $this->assertFalse($secondReservation->getRateLimit()->isAccepted()); + $this->assertEquals(60, ceil($firstReservation->getWaitDuration())); + $this->assertEquals(120, ceil($secondReservation->getWaitDuration())); + } + public function testWaitIntervalOnConsumeOverLimit() { $limiter = $this->createLimiter(); From c0ae0482c32e693c1c4d127b3446c4b880794542 Mon Sep 17 00:00:00 2001 From: SanderSander Date: Wed, 1 Nov 2023 22:50:42 +0100 Subject: [PATCH 2/2] CS --- src/Symfony/Component/RateLimiter/Policy/Window.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/RateLimiter/Policy/Window.php b/src/Symfony/Component/RateLimiter/Policy/Window.php index 42d65f6483a07..49eddf3e7d46e 100644 --- a/src/Symfony/Component/RateLimiter/Policy/Window.php +++ b/src/Symfony/Component/RateLimiter/Policy/Window.php @@ -78,6 +78,7 @@ public function calculateTimeForTokens(int $tokens, float $now): int } $inWindow = ceil($this->hitCount / $this->maxSize); + return (int) ceil($this->timer + ($this->intervalInSeconds * $inWindow) - $now); }