nikolaposa / rate-limit

🚔 General purpose rate limiter implementation.
MIT License
269 stars 47 forks source link

Simulating real minutes #51

Closed Eligioo closed 2 years ago

Eligioo commented 2 years ago

Hi @nikolaposa

With the Rate::custom I'm trying to simulate real minutes (12:00, 12:01, 12:02, etc.) rather than 1 minute based on the first call (12:00:30 --> 12:01:30). I tried it with the following setup:

$now = Carbon::now();
$nextMinute = $now->copy()->addMinute()->second(1); // Add extra second for a safe margin which gives you 12:01:01
$rate = Rate::custom(5, $now->diffInSeconds($nextMinute));

$rateLimiter = new RedisRateLimiter($redis);
$status = $rateLimiter->limitSilently($key, $rate);

The $status->getResetAt() gets calculated correctly but the problem I'm facing is that the $status->getRemainingAttempts() resets every second. This is probably due to the $now->diffInSeconds($nextMinute) used for the custom rate changes every second. Any suggestion on how to make this work?

nikolaposa commented 2 years ago

Hi 👋

May I ask why would you need something like that, is there any particular scenario you are facing? I don't think something like that is possible, since Rate->interval is always a time interval in seconds, there's no way to specify exact minutes.

I think the only way to achieve what you want is to change the way key is generated as in case of Redis backend for example: https://github.com/nikolaposa/rate-limit/blob/master/src/RedisRateLimiter.php#L42.

Eligioo commented 2 years ago

Thank you for your answer. The scenario I'm facing is that the external system I'm trying to rate limit against is working with real minutes hence I try to simulate that. But the system doesn't provide the information on how much calls I have left per clock minute.

Can you be more explicit what you meant with the way the key is generated?

Eligioo commented 2 years ago

Ok I figured out what you meant with the generated Redis key! Now I also understand why it resets every second. It's because the interval is suffixed to the Redis key. I'll look into it! Thanks for giving me a direction.

UPDATE: Removing the :$interval in private function key already does the trick but I'll come up with something better.

nikolaposa commented 2 years ago

Exactly, so what I meant is basically some custom strategy for generating keys such as: $key:$minute or something like that. Not sure, but I think that even custom Rate implementation is needed.

Eligioo commented 2 years ago

Yes that's what I exactly did, create a new RedisRateLimiter with a modified key method. It's working as expected now.