-
Notifications
You must be signed in to change notification settings - Fork 2
Description
So I'm not sure if this belongs in this gem but I feel like it's a fairly common use case. If it doesn't belong directly in the gem perhaps an example in the readme could help someone?
So I needed to rate limit a particular method but rather than just skipping the execution if the limit was hit, I needed to always guarantee the method was eventually executed. So I combine ExcessFlow with a simple while (true) and a sleep such that eventually the method completes once it can without violating the limit.
Here is my code. Also if I missed something already built into the gem that does this easier please let me know!
module RateLimit
module_function
def limit(unique_throttle_name, rate, interval, &block)
while true
execution = ExcessFlow.throttle(options(unique_throttle_name, rate, interval)) do
block.call
end
if execution.success?
return execution.result
else
time_to_wait = interval + 1
time_to_wait = rand(0.0..time_to_wait.to_f)
puts "Rate limited - waiting a random amount of time #{time_to_wait}"
sleep time_to_wait
end
end
end
def options(name, rate, interval)
{ key: name.to_s, limit: rate, ttl: interval }
end
end
Usage:
RateLimit.limit("rate-limit-some-unique-name', 1, 10) do
puts "Performing this block once, no more than every 10 seconds"
end
I run this code inside some sidekiq workers that run asynchronously so I can safely guarantee across processes that the block doesn't execute more than it should, but it still eventually executes.