Description
Symfony version(s) affected
6.1.2
Description
Based on this part of the documentation : https://symfony.com/doc/current/rate_limiter.html#exposing-the-rate-limiter-status
We can retrieve the statuses of the RateLimiter.
$limiter = $anonymousApiLimiter->create($request->getClientIp());
$limit = $limiter->consume();
$headers = [
'X-RateLimit-Remaining' => $limit->getRemainingTokens(),
'X-RateLimit-Retry-After' => $limit->getRetryAfter()->getTimestamp(),
'X-RateLimit-Limit' => $limit->getLimit(),
];
But the retryAfter does not return interesting information in the current case in my opinion.
Take for example this configuration with fixed_window rate limiter :
rate_limiter.yaml
framework:
rate_limiter:
custom_thing:
policy: 'fixed_window'
limit: 5
interval: '60 minutes'
And we use it :
public function myControllerAction(RateLimiterFactory $customThingLimiter): void
{
$limiter = $customThingLimiter->create('custom_thing_limit');
$limit = $limiter->consume();
$headers = [
'X-RateLimit-Remaining' => $limit->getRemainingTokens(),
'X-RateLimit-Retry-After' => $limit->getRetryAfter()->getTimestamp(),
'X-RateLimit-Limit' => $limit->getLimit(),
];
dump($headers);
//...
}
Now let's start with this:
- We can make 5 requests by hour
- The first request of the interval begin at 10:05
- The last request of the interval begin at 10:45
From this moment, the user is supposed to be able to make 5 new requests 1 hour after making the very 1st request of the interval, so : 11:05AM
During the 5 requests, the value of $limit->getRetryAfter()
will be the current date, which is OK.
If after my 5 requests, I try a new request (Who therefore should not be accepted), the value of $limit->getRetryAfter()
should be something like : 2022-07-07 11:05
because I started the first interval request at 10:05.
But, his value will be something like : 2022-07-07 11:45
. It just added 1 hour from the last request date, and not from the first interval request date.
Now, it's 10:50, I still shouldn't be able to reapply. If I try one, it won't be consumed. The value of $limit->getRetryAfter()
should be, a new time 11:05
. But it will be 11:50
(One hour after last request date).
The value of retryAfter is meant to represent the date from which a user is expected to be able to make at least one request again.
But, as we can see, that will not be the case.
How to reproduce
Follow the reproducer : https://github.com/bastien70/symfony-rate-limiter/tree/main
Instructions are on the README.
Here's what you might get as results from first request :
At this moment, the retryAfter should already be the date of the 1st request, plus 1 hour, so 15:30:51
.
At this moment, it just added 1 hour to the CURRENT date (should be to the FIRST interval request date)
A new time, it just added 1 hour to the CURRENT date
Same thing for next tries.
Possible Solution
-
Keep in memory the exact date of the 1st request of the interval.
-
When the last request is consumed, then that's when it should add 1 hour to the retryAfter, but still from the 1st request.
-
If the user retries, then the retryAfter date will not change until the interval is over.
Additional Context
No response