class Logster::RedisRateLimiter
Constants
- BUCKETS
- PREFIX
Attributes
callback[R]
duration[R]
Public Class Methods
clear_all(redis, redis_prefix = nil)
click to toggle source
# File lib/logster/redis_rate_limiter.rb, line 10 def self.clear_all(redis, redis_prefix = nil) prefix = key_prefix(redis_prefix) redis.eval " local keys = redis.call('keys', '*#{prefix}*') if (table.getn(keys) > 0) then redis.call('del', unpack(keys)) end " end
new(redis, severities, limit, duration, redis_prefix = nil, callback = nil)
click to toggle source
# File lib/logster/redis_rate_limiter.rb, line 21 def initialize(redis, severities, limit, duration, redis_prefix = nil, callback = nil) @severities = severities @limit = limit @duration = duration @callback = callback @redis_prefix = redis_prefix @redis = redis @bucket_range = @duration / BUCKETS @mget_keys = (0..(BUCKETS - 1)).map { |i| "#{key}:#{i}" } end
Private Class Methods
key_prefix(redis_prefix)
click to toggle source
# File lib/logster/redis_rate_limiter.rb, line 83 def self.key_prefix(redis_prefix) if redis_prefix "#{redis_prefix.call}:#{PREFIX}" else PREFIX end end
Public Instance Methods
callback_key()
click to toggle source
# File lib/logster/redis_rate_limiter.rb, line 77 def callback_key "#{key}:callback_triggered" end
check(severity)
click to toggle source
# File lib/logster/redis_rate_limiter.rb, line 36 def check(severity) return unless @severities.include?(severity) time = Time.now.to_i num = bucket_number(time) redis_key = "#{key}:#{num}" current_rate = @redis.eval <<-LUA local bucket_number = #{num} local bucket_count = redis.call("INCR", "#{redis_key}") if bucket_count == 1 then redis.call("EXPIRE", "#{redis_key}", "#{bucket_expiry(time)}") redis.call("DEL", "#{callback_key}") end local function retrieve_rate () local sum = 0 local values = redis.call("MGET", #{mget_keys(num)}) for index, value in ipairs(values) do if value ~= false then sum = sum + value end end return sum end return (retrieve_rate() + bucket_count) LUA if !@redis.get(callback_key) && (current_rate >= @limit) @callback.call(current_rate) if @callback @redis.set(callback_key, 1) end current_rate end
key()
click to toggle source
# File lib/logster/redis_rate_limiter.rb, line 71 def key # "_LOGSTER_RATE_LIMIT:012:20:30" # Triggers callback when log levels of :debug, :info and :warn occurs 20 times within 30 secs "#{key_prefix}:#{@severities.join("")}:#{@limit}:#{@duration}" end
retrieve_rate()
click to toggle source
# File lib/logster/redis_rate_limiter.rb, line 32 def retrieve_rate @redis.mget(@mget_keys).reduce(0) { |sum, value| sum + value.to_i } end
Private Instance Methods
bucket_expiry(time)
click to toggle source
# File lib/logster/redis_rate_limiter.rb, line 106 def bucket_expiry(time) @duration - ((time % @duration) % @bucket_range) end
bucket_number(time)
click to toggle source
# File lib/logster/redis_rate_limiter.rb, line 102 def bucket_number(time) (time % @duration) / @bucket_range end
key_prefix()
click to toggle source
# File lib/logster/redis_rate_limiter.rb, line 92 def key_prefix self.class.key_prefix(@redis_prefix) end
mget_keys(bucket_num)
click to toggle source
# File lib/logster/redis_rate_limiter.rb, line 96 def mget_keys(bucket_num) keys = @mget_keys.dup keys.delete_at(bucket_num) keys.map { |key| "'#{key}'" }.join(', ') end