Class: Istox::RateLimit
- Inherits:
-
Object
- Object
- Istox::RateLimit
- Defined in:
- lib/istox/helpers/rate_limit.rb
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.
-
#limit!(subject, options = {}) ⇒ Object
Raise error if exceeded the limit.
-
#limit?(subject, options = {}) ⇒ Boolean
Return false if exceeded the limit, else return true.
-
#within_bounds?(subject, options = {}) ⇒ Boolean
Check if the rate limit is within bounds.
Constructor Details
#initialize(key, options = {}) ⇒ Ratelimit
Create a Ratelimit object.
Cannot be larger than the bucket_span.
20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
# File 'lib/istox/helpers/rate_limit.rb', line 20 def initialize(key, = {}) @key = key raise ArgumentError, 'Redis object is now passed in via the options hash - options[:redis]' unless .is_a?(Hash) @bucket_span = [:bucket_span] || 600 @bucket_interval = [:bucket_interval] || 5 @bucket_expiry = [:bucket_expiry] || @bucket_span raise ArgumentError, 'Bucket expiry cannot be larger than the bucket span' if @bucket_expiry > @bucket_span @bucket_count = (@bucket_span / @bucket_interval).round raise ArgumentError, 'Cannot have less than 3 buckets' if @bucket_count < 3 @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/istox/helpers/rate_limit.rb', line 41 def add(subject, count = 1) bucket = get_bucket subject = "#{@key}:#{subject}" redis.multi do redis.hincrby(subject, bucket, count) redis.hdel(subject, (bucket + 1) % @bucket_count) redis.hdel(subject, (bucket + 2) % @bucket_count) redis.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/istox/helpers/rate_limit.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 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/istox/helpers/rate_limit.rb', line 74 def exceeded?(subject, = {}) 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.
130 131 132 133 134 135 |
# File 'lib/istox/helpers/rate_limit.rb', line 130 def exec_within_threshold(subject, = {}) [:threshold] ||= 30 [:interval] ||= 30 sleep @bucket_interval while exceeded?(subject, ) yield(self) end |
#limit!(subject, options = {}) ⇒ Object
Raise error if exceeded the limit
94 95 96 97 98 |
# File 'lib/istox/helpers/rate_limit.rb', line 94 def limit!(subject, = {}) raise ::Istox::RateLimitExceedError if exceeded?(subject, ) add(subject) end |
#limit?(subject, options = {}) ⇒ Boolean
Return false if exceeded the limit, else return true
106 107 108 109 110 111 112 113 114 |
# File 'lib/istox/helpers/rate_limit.rb', line 106 def limit?(subject, = {}) result = within_bounds?(subject, ) return result unless result add(subject) true end |
#within_bounds?(subject, options = {}) ⇒ Boolean
Check if the rate limit is within bounds
84 85 86 |
# File 'lib/istox/helpers/rate_limit.rb', line 84 def within_bounds?(subject, = {}) !exceeded?(subject, ) end |