Closed kevinastone closed 8 years ago
Hi,
Thank you for this idea. I'd like to take some time to think about it.
However, when it comes to your particular problem, I'd suggest using plain ETS. I recently implemented a basic rate limiter for my blog. You can find the source here.
The idea is to start a process which will create a named ETS table that is completely purged in regular interval:
Erlangelist.RateLimiter.start_link(:per_minute, :timer.minutes(1))
Then you can call allow?
from any process to increase the count by 1 and immediately get the response whether you can carry on or not:
Erlangelist.RateLimiter.allow?(:per_minute, operation_key, max_rate)
The operation_key
is arbitrary term that uniquely identifies your operation. You can use a single table to enforce different limits on different operations.
However, if you want to use different intervals, you'll need to start one process per each interval.
Note that allow?
is executed in the caller process, so there's no single process bottleneck. The owner process is only used to periodically purge the table.
Note: this code will work only in Erlang 18, because it relies on a new variant of :ets.update/4
. It could be implemented for earlier versions as well, but some trade-offs must be made.
Awesome, thanks for the link.
No problem. I didn't publish it as a lib, because it's so small, but the code is MIT licensed, so basically feel free to copy-paste it and do whatever you want with it. Of course, I hold no responsibility :-)
Feel free to ping me if you get stuck.
This is now supported through #16
It would be nice to prevent touching the TTL when updating. I'm using con_cache as a rate limit store, so it should simply expire after a duration after the key is first created. Updates wouldn't affect the ttl.
Looking for something like: