From 233f00e6b8ed7076ef0622ee55f452082aa3e0b6 Mon Sep 17 00:00:00 2001 From: Ilona Date: Wed, 16 Aug 2023 15:13:46 +0200 Subject: [PATCH 1/4] issue-51401: Add custom limit to RateLimiterFactory Add an optional custom limit to the RateLimiterFactory to overwrite configured values. --- .../RateLimiter/RateLimiterFactory.php | 12 ++++++++---- .../Tests/RateLimiterFactoryTest.php | 17 +++++++++++++++++ 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/RateLimiter/RateLimiterFactory.php b/src/Symfony/Component/RateLimiter/RateLimiterFactory.php index 1b397ac8af0bc..b8aaecbafb25b 100644 --- a/src/Symfony/Component/RateLimiter/RateLimiterFactory.php +++ b/src/Symfony/Component/RateLimiter/RateLimiterFactory.php @@ -41,15 +41,19 @@ public function __construct(array $config, StorageInterface $storage, LockFactor $this->config = $options->resolve($config); } - public function create(string $key = null): LimiterInterface + /** + * Parsing a custom limit to this function will overwrite the limit in your configuration for this request. + */ + public function create(string $key = null, ?int $limit = null): LimiterInterface { $id = $this->config['id'].'-'.$key; $lock = $this->lockFactory?->createLock($id); + $limit = $limit ?? $this->config['limit']; return match ($this->config['policy']) { - 'token_bucket' => new TokenBucketLimiter($id, $this->config['limit'], $this->config['rate'], $this->storage, $lock), - 'fixed_window' => new FixedWindowLimiter($id, $this->config['limit'], $this->config['interval'], $this->storage, $lock), - 'sliding_window' => new SlidingWindowLimiter($id, $this->config['limit'], $this->config['interval'], $this->storage, $lock), + 'token_bucket' => new TokenBucketLimiter($id, $limit, $this->config['rate'], $this->storage, $lock), + 'fixed_window' => new FixedWindowLimiter($id, $limit, $this->config['interval'], $this->storage, $lock), + 'sliding_window' => new SlidingWindowLimiter($id, $limit, $this->config['interval'], $this->storage, $lock), 'no_limit' => new NoLimiter(), default => throw new \LogicException(sprintf('Limiter policy "%s" does not exists, it must be either "token_bucket", "sliding_window", "fixed_window" or "no_limit".', $this->config['policy'])), }; diff --git a/src/Symfony/Component/RateLimiter/Tests/RateLimiterFactoryTest.php b/src/Symfony/Component/RateLimiter/Tests/RateLimiterFactoryTest.php index 5ac5963a2a1cb..f0ff1053c246b 100644 --- a/src/Symfony/Component/RateLimiter/Tests/RateLimiterFactoryTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/RateLimiterFactoryTest.php @@ -70,6 +70,23 @@ public function testInvalidConfig(string $exceptionClass, array $config) $factory->create('key'); } + public function testCustomLimit() + { + $factory = new RateLimiterFactory( + [ + 'policy' => 'sliding_window', + 'id' => 'test', + 'limit' => 5, + 'interval' => '5 seconds', + ], + new InMemoryStorage() + ); + + $rateLimiter = $factory->create('key', 10); + $rateLimit = $rateLimiter->consume(0); + $this->assertSame(10, $rateLimit->getRemainingTokens()); + } + public static function invalidConfigProvider() { yield [MissingOptionsException::class, [ From 9a07f1638223ec6b23d156042b1df7b3cb9af4ba Mon Sep 17 00:00:00 2001 From: Ilona Date: Wed, 16 Aug 2023 15:19:41 +0200 Subject: [PATCH 2/4] issue-51401: Fix codestyle Removed unneeded `?` --- src/Symfony/Component/RateLimiter/RateLimiterFactory.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/RateLimiter/RateLimiterFactory.php b/src/Symfony/Component/RateLimiter/RateLimiterFactory.php index b8aaecbafb25b..2fb1267698f82 100644 --- a/src/Symfony/Component/RateLimiter/RateLimiterFactory.php +++ b/src/Symfony/Component/RateLimiter/RateLimiterFactory.php @@ -44,7 +44,7 @@ public function __construct(array $config, StorageInterface $storage, LockFactor /** * Parsing a custom limit to this function will overwrite the limit in your configuration for this request. */ - public function create(string $key = null, ?int $limit = null): LimiterInterface + public function create(string $key = null, int $limit = null): LimiterInterface { $id = $this->config['id'].'-'.$key; $lock = $this->lockFactory?->createLock($id); From 484a11c543aedf53f92e175ba6989d806ab45cc8 Mon Sep 17 00:00:00 2001 From: Ilona Date: Wed, 16 Aug 2023 15:33:43 +0200 Subject: [PATCH 3/4] issue-51401: Remove fetching of limit for no-limit limiter --- src/Symfony/Component/RateLimiter/RateLimiterFactory.php | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/RateLimiter/RateLimiterFactory.php b/src/Symfony/Component/RateLimiter/RateLimiterFactory.php index 2fb1267698f82..377d872eed28f 100644 --- a/src/Symfony/Component/RateLimiter/RateLimiterFactory.php +++ b/src/Symfony/Component/RateLimiter/RateLimiterFactory.php @@ -48,12 +48,11 @@ public function create(string $key = null, int $limit = null): LimiterInterface { $id = $this->config['id'].'-'.$key; $lock = $this->lockFactory?->createLock($id); - $limit = $limit ?? $this->config['limit']; return match ($this->config['policy']) { - 'token_bucket' => new TokenBucketLimiter($id, $limit, $this->config['rate'], $this->storage, $lock), - 'fixed_window' => new FixedWindowLimiter($id, $limit, $this->config['interval'], $this->storage, $lock), - 'sliding_window' => new SlidingWindowLimiter($id, $limit, $this->config['interval'], $this->storage, $lock), + 'token_bucket' => new TokenBucketLimiter($id, $limit ?? $this->config['limit'], $this->config['rate'], $this->storage, $lock), + 'fixed_window' => new FixedWindowLimiter($id, $limit ?? $this->config['limit'], $this->config['interval'], $this->storage, $lock), + 'sliding_window' => new SlidingWindowLimiter($id, $limit ?? $this->config['limit'], $this->config['interval'], $this->storage, $lock), 'no_limit' => new NoLimiter(), default => throw new \LogicException(sprintf('Limiter policy "%s" does not exists, it must be either "token_bucket", "sliding_window", "fixed_window" or "no_limit".', $this->config['policy'])), }; From 2cbaa14c5bc4524f0188292155e7af1fa8508ec5 Mon Sep 17 00:00:00 2001 From: Ilona Date: Thu, 17 Aug 2023 09:06:35 +0200 Subject: [PATCH 4/4] issue-51401: Add line of doc --- src/Symfony/Component/RateLimiter/RateLimiterFactory.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/RateLimiter/RateLimiterFactory.php b/src/Symfony/Component/RateLimiter/RateLimiterFactory.php index 377d872eed28f..383e44993030d 100644 --- a/src/Symfony/Component/RateLimiter/RateLimiterFactory.php +++ b/src/Symfony/Component/RateLimiter/RateLimiterFactory.php @@ -43,6 +43,7 @@ public function __construct(array $config, StorageInterface $storage, LockFactor /** * Parsing a custom limit to this function will overwrite the limit in your configuration for this request. + * When using a NoLimiter the limit will be ignored. */ public function create(string $key = null, int $limit = null): LimiterInterface {