Skip to content

Commit 668dde3

Browse files
committed
[RateLimiter] Added the docs for the new component
1 parent 707580e commit 668dde3

File tree

2 files changed

+166
-0
lines changed

2 files changed

+166
-0
lines changed

index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ Topics
5252
notifier
5353
performance
5454
profiler
55+
rate_limiter
5556
routing
5657
security
5758
session

rate_limiter.rst

Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
Rate Limiter
2+
============
3+
4+
.. versionadded:: 5.2
5+
6+
The RateLimiter component was introduced in Symfony 5.2 as an
7+
:doc:`experimental feature </contributing/code/experimental>`.
8+
9+
A "rate limiter" controls how frequently some event (e.g. an HTTP request or a
10+
login attempt) is allowed to happen. It implements a `token bucket algorithm`_,
11+
which roughly works like this:
12+
13+
* A bucket is initially created with zero or more tokens;
14+
* A new token is added to the bucket with a predefined frequency (e.g. every second);
15+
* Allowing an event consumes one or more tokens;
16+
* If the bucket still contains tokens, the event is allowed; otherwise, it's denied;
17+
* If the bucket is at full capacity, new tokens are discarded.
18+
19+
Symfony uses these rate limiters in built-in features like "login throttling",
20+
which limits how many failed login attempts a user can make in a given period of
21+
time, but you can use them for your own features too.
22+
23+
Installation
24+
------------
25+
26+
Before using a rate limiter for the first time, run the following command to
27+
install the associated Symfony Component in your application:
28+
29+
.. code-block:: terminal
30+
31+
$ composer require symfony/rate-limiter
32+
33+
Configuration
34+
-------------
35+
36+
Use the following options to configure the behavior of the rate limiter:
37+
38+
.. code-block:: yaml
39+
40+
# config/packages/rate_limiter.yaml
41+
framework:
42+
rate_limiter:
43+
limiters:
44+
api_requests:
45+
# maximum number of tokens allowed in the bucket
46+
limit: 100
47+
# how many tokens are created and how often
48+
rate:
49+
amount: 100
50+
interval: '1 hour'
51+
52+
This example creates a rate limiter to restrict the number of HTTP requests of
53+
some API to 100 per hour.
54+
55+
There are other options that you can optionally define if needed:
56+
57+
.. code-block:: yaml
58+
59+
# config/packages/rate_limiter.yaml
60+
framework:
61+
rate_limiter:
62+
limiters:
63+
api_requests:
64+
# ...
65+
lock:
66+
storage:
67+
strategy:
68+
interval:
69+
70+
Rate Limiting in Action
71+
-----------------------
72+
73+
After having installed and configured the rate limiter, inject it in any service
74+
or controller and call the ``consume()`` method to try to consume a given number
75+
of tokens. For example, this controller uses the previous rate limiter to control
76+
the number of requests to the API::
77+
78+
// src/Controller/LuckyController.php
79+
namespace App\Controller;
80+
81+
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
82+
use Symfony\Component\HttpKernel\Exception\TooManyRequestsHttpException;
83+
use Symfony\Component\RateLimiter\LimiterInterface;
84+
85+
class ApiController extends AbstractController
86+
{
87+
public function index(LimiterInterface $limiter)
88+
{
89+
// the argument of consume() is the number of tokens to consume
90+
// and returns FALSE if they cannot be consumed
91+
if (false === $limiter->consume(1)) {
92+
throw new TooManyRequestsHttpException();
93+
}
94+
95+
// ...
96+
}
97+
98+
// ...
99+
}
100+
101+
.. note::
102+
103+
In a real application, instead of checking the rate limiter in all the API
104+
controller methods, create an :ref:`event listener or subscriber </event_dispatcher>`
105+
for the :ref:`kernel.request event <component-http-kernel-kernel-request>`
106+
and check the rate limiter once for all requests.
107+
108+
In other scenarios you may want instead to wait as long as needed until a new
109+
token is available. In those cases, use the ``reserve()`` and ``wait()`` methods::
110+
111+
// src/Controller/LuckyController.php
112+
// ...
113+
114+
class ApiController extends AbstractController
115+
{
116+
public function registerUser(LimiterInterface $limiter)
117+
{
118+
// this blocks the application until the given number of tokens can be consumed
119+
$limiter->reserve(1)->wait();
120+
121+
// ...
122+
}
123+
124+
// ...
125+
}
126+
127+
Creating Multiple Rate Limiters
128+
-------------------------------
129+
130+
You can define any number of rate limiters in the application. For example, you
131+
could set different API request limits for anonymous and authenticated users:
132+
133+
.. code-block:: yaml
134+
135+
# config/packages/rate_limiter.yaml
136+
framework:
137+
rate_limiter:
138+
limiters:
139+
# 1 request per minute for anonymous users
140+
anonymous_api_requests:
141+
limit: 1
142+
rate:
143+
amount: 1
144+
interval: '1 minute'
145+
# 85 requests per minute for authenticated users
146+
authenticated_api_requests:
147+
limit: 85
148+
rate:
149+
amount: 85
150+
interval: '1 minute'
151+
152+
Now you can inject each rate limiter using the same name as in the configuration::
153+
154+
// src/Controller/LuckyController.php
155+
// ...
156+
157+
class ApiController extends AbstractController
158+
{
159+
public function index(LimiterInterface $authenticated_api_requests)
160+
{
161+
// ...
162+
}
163+
}
164+
165+
.. _`token bucket algorithm`: https://en.wikipedia.org/wiki/Token_bucket

0 commit comments

Comments
 (0)