Class: Ratelimit
- Inherits:
-
Object
- Object
- Ratelimit
- Defined in:
- lib/ratelimit.rb,
lib/ratelimit/version.rb
Constant Summary collapse
- VERSION =
"1.0.4"
Instance Method Summary collapse
-
#add(subject, count = 1) ⇒ Integer
Add to the counter for a given subject.
-
#count(subject, interval) ⇒ Object
Returns the count for a given subject and interval.
-
#exceeded?(subject, options = {}) ⇒ Boolean
Check if the rate limit has been exceeded.
-
#exec_within_threshold(subject, options = {}) { ... } ⇒ Object
Execute a block once the rate limit is within bounds WARNING This will block the current thread until the rate limit is within bounds.
-
#initialize(key, options = {}) ⇒ Ratelimit
constructor
Create a Ratelimit object.
-
#within_bounds?(subject, options = {}) ⇒ Boolean
Check if the rate limit is within bounds.
Constructor Details
#initialize(key, options = {}) ⇒ Ratelimit
Create a Ratelimit object.
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/ratelimit.rb', line 17 def initialize(key, = {}) @key = key unless .is_a?(Hash) raise ArgumentError.new("Redis object is now passed in via the options hash - options[:redis]") end @bucket_span = [:bucket_span] || 600 @bucket_interval = [:bucket_interval] || 5 @bucket_expiry = [:bucket_expiry] || @bucket_span if @bucket_expiry > @bucket_span raise ArgumentError.new("Bucket expiry cannot be larger than the bucket span") end @bucket_count = (@bucket_span / @bucket_interval).round if @bucket_count < 3 raise ArgumentError.new("Cannot have less than 3 buckets") end @raw_redis = [:redis] end |
Instance Method Details
#add(subject, count = 1) ⇒ Integer
Add to the counter for a given subject.
41 42 43 44 45 46 47 48 49 50 |
# File 'lib/ratelimit.rb', line 41 def add(subject, count = 1) bucket = get_bucket subject = "#{@key}:#{subject}" redis.multi do |transaction| transaction.hincrby(subject, bucket, count) transaction.hdel(subject, (bucket + 1) % @bucket_count) transaction.hdel(subject, (bucket + 2) % @bucket_count) transaction.expire(subject, @bucket_expiry) end.first end |
#count(subject, interval) ⇒ Object
Returns the count for a given subject and interval
56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/ratelimit.rb', line 56 def count(subject, interval) bucket = get_bucket interval = [[interval, @bucket_interval].max, @bucket_span].min count = (interval / @bucket_interval).floor subject = "#{@key}:#{subject}" keys = (0..count - 1).map do |i| (bucket - i) % @bucket_count end return redis.hmget(subject, *keys).inject(0) {|a, i| a + i.to_i} end |
#exceeded?(subject, options = {}) ⇒ Boolean
Check if the rate limit has been exceeded.
74 75 76 |
# File 'lib/ratelimit.rb', line 74 def exceeded?(subject, = {}) return count(subject, [:interval]) >= [:threshold] end |
#exec_within_threshold(subject, options = {}) { ... } ⇒ Object
Execute a block once the rate limit is within bounds WARNING This will block the current thread until the rate limit is within bounds.
102 103 104 105 106 107 108 109 |
# File 'lib/ratelimit.rb', line 102 def exec_within_threshold(subject, = {}, &block) [:threshold] ||= 30 [:interval] ||= 30 while exceeded?(subject, ) sleep @bucket_interval end yield(self) end |
#within_bounds?(subject, options = {}) ⇒ Boolean
Check if the rate limit is within bounds
84 85 86 |
# File 'lib/ratelimit.rb', line 84 def within_bounds?(subject, = {}) return !exceeded?(subject, ) end |