-
Notifications
You must be signed in to change notification settings - Fork 80
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Searching new maintainer #19
Labels
Comments
4 tasks
fabpot
added a commit
to symfony/symfony
that referenced
this issue
Sep 16, 2020
This PR was squashed before being merged into the 5.2-dev branch. Discussion ---------- [RFC] Introduce a RateLimiter component | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | Refs #37444 | License | MIT | Doc PR | tbd Based on the discussions in #37444, I decided to write a general purpose RateLimiter component. This implementation uses the token bucket algorithm, inspired by the [Go's time/rate](https://github.com/golang/time/blob/3af7569d3a1e776fc2a3c1cec133b43105ea9c2e/rate/rate.go) library and the [PHP `bandwidth-throttle/token-bucket` package](https://github.com/bandwidth-throttle/token-bucket) (which is [unmaintained for years](bandwidth-throttle/token-bucket#19)). ### Usage The component has two main methods: * `Limiter::reserve(int $tokens, int $maxTime)`, allocates `$tokens` and returns a `Reservation` containing the wait time. Use this method if your process wants to wait before consuming the token. * `Limiter::consume(int $tokens)`, checks if `$tokens` are available now and discards the reservation if that's not the case. Use this method if you want to skip when there are not enough tokens at this moment. The component uses the Lock component to make sure it can be used in parallel processes. Example: ```php <?php namespace App\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\RateLimiter\LimiterFactory; class LimitListener { private $limiterFactory; public function __construct(LimiterFactory $apiLimiterFactory) { $this->limiterFactory = $apiLimiterFactory; } public function __invoke(RequestEvent $event) { $ip = $event->getRequest()->getClientIp(); $limiter = $this->limiterFactory->createLimiter(preg_replace('/[^a-zA-Z0-9]/', '-', $ip)); if (!$limiter->consume()) { $event->setResponse(new Response('Too many requests', 429)); } } } ``` ### Usefullness of the component I think a generic rate limiter is usefull in quite some places: * Add a login throttling feature in Symfony * <s>Rate limiting outgoing API calls (e.g. HttpClient), to prevent hitting upstream API limits.</s> See #37471 (and https://blog.heroku.com/rate-throttle-api-client ) * Allowing users to easily implement API rate limits in their own Symfony-based APIs. ### State of the art There are some rate limiting packages in PHP, but I think there is no precendent for this component: * [`graham-campbell/throttle`](https://github.com/GrahamCampbell/Laravel-Throttle) is heavily relying on Laravel. It is however very popular, proofing there is a need for such feature * [`nikolaposa/rate-limit`](https://github.com/nikolaposa/rate-limit) does not implement reservation of tokens and as such less feature complete. Also its architecture combines the rate limiter and storage, making it harder to implement different storages. ### Todo If it is agreed that this component can bring something to Symfony, it needs some more love: * [x] Add more tests * [x] Integrate with the FrameworkBundle * [x] Add sliding window implementation * [x] Add integration with the Security component * <s>Maybe add more storage implementations? I didn't want to duplicate storage functionalities already existing in the Lock and Cache component, thus I for now focused mostly on integrating the Cache adapters. But maybe a special Doctrine adapter makes sense?</s> Commits ------- 67417a6 [RFC] Introduce a RateLimiter component
symfony-splitter
pushed a commit
to symfony/lock
that referenced
this issue
Sep 16, 2020
This PR was squashed before being merged into the 5.2-dev branch. Discussion ---------- [RFC] Introduce a RateLimiter component | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | Deprecations? | no | Tickets | Refs #37444 | License | MIT | Doc PR | tbd Based on the discussions in #37444, I decided to write a general purpose RateLimiter component. This implementation uses the token bucket algorithm, inspired by the [Go's time/rate](https://github.com/golang/time/blob/3af7569d3a1e776fc2a3c1cec133b43105ea9c2e/rate/rate.go) library and the [PHP `bandwidth-throttle/token-bucket` package](https://github.com/bandwidth-throttle/token-bucket) (which is [unmaintained for years](bandwidth-throttle/token-bucket#19)). ### Usage The component has two main methods: * `Limiter::reserve(int $tokens, int $maxTime)`, allocates `$tokens` and returns a `Reservation` containing the wait time. Use this method if your process wants to wait before consuming the token. * `Limiter::consume(int $tokens)`, checks if `$tokens` are available now and discards the reservation if that's not the case. Use this method if you want to skip when there are not enough tokens at this moment. The component uses the Lock component to make sure it can be used in parallel processes. Example: ```php <?php namespace App\EventListener; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\RateLimiter\LimiterFactory; class LimitListener { private $limiterFactory; public function __construct(LimiterFactory $apiLimiterFactory) { $this->limiterFactory = $apiLimiterFactory; } public function __invoke(RequestEvent $event) { $ip = $event->getRequest()->getClientIp(); $limiter = $this->limiterFactory->createLimiter(preg_replace('/[^a-zA-Z0-9]/', '-', $ip)); if (!$limiter->consume()) { $event->setResponse(new Response('Too many requests', 429)); } } } ``` ### Usefullness of the component I think a generic rate limiter is usefull in quite some places: * Add a login throttling feature in Symfony * <s>Rate limiting outgoing API calls (e.g. HttpClient), to prevent hitting upstream API limits.</s> See #37471 (and https://blog.heroku.com/rate-throttle-api-client ) * Allowing users to easily implement API rate limits in their own Symfony-based APIs. ### State of the art There are some rate limiting packages in PHP, but I think there is no precendent for this component: * [`graham-campbell/throttle`](https://github.com/GrahamCampbell/Laravel-Throttle) is heavily relying on Laravel. It is however very popular, proofing there is a need for such feature * [`nikolaposa/rate-limit`](https://github.com/nikolaposa/rate-limit) does not implement reservation of tokens and as such less feature complete. Also its architecture combines the rate limiter and storage, making it harder to implement different storages. ### Todo If it is agreed that this component can bring something to Symfony, it needs some more love: * [x] Add more tests * [x] Integrate with the FrameworkBundle * [x] Add sliding window implementation * [x] Add integration with the Security component * <s>Maybe add more storage implementations? I didn't want to duplicate storage functionalities already existing in the Lock and Cache component, thus I for now focused mostly on integrating the Cache adapters. But maybe a special Doctrine adapter makes sense?</s> Commits ------- 67417a693e [RFC] Introduce a RateLimiter component
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This project searches for a new maintainer. Please volunteer.
The text was updated successfully, but these errors were encountered: