class Berater::Limiter
Attributes
args[R]
capacity[R]
key[R]
options[R]
Public Class Methods
new(key, capacity, *args, **opts)
click to toggle source
# File lib/berater/limiter.rb, line 71 def initialize(key, capacity, *args, **opts) @key = key self.capacity = capacity @args = args @options = opts end
Protected Class Methods
cache_key(key)
click to toggle source
# File lib/berater/limiter.rb, line 109 def cache_key(key) klass = to_s.split(':')[-1] "Berater:#{klass}:#{key}" end
inherited(subclass)
click to toggle source
# File lib/berater/limiter.rb, line 116 def inherited(subclass) # automagically create convenience method name = subclass.to_s.split(':')[-1] Berater.define_singleton_method(name) do |*args, **opts, &block| Berater::Utils.convenience_fn(subclass, *args, **opts, &block) end end
new(*)
click to toggle source
Calls superclass method
# File lib/berater/limiter.rb, line 102 def new(*) # can only call via subclass raise NoMethodError if self == Berater::Limiter super end
Public Instance Methods
==(other)
click to toggle source
# File lib/berater/limiter.rb, line 58 def ==(other) self.class == other.class && self.key == other.key && self.capacity == other.capacity && self.args == other.args && self.options == other.options && self.redis.connection == other.redis.connection end
limit(capacity: nil, cost: 1) { |lock| ... }
click to toggle source
# File lib/berater/limiter.rb, line 10 def limit(capacity: nil, cost: 1, &block) capacity ||= @capacity lock = nil Berater.middleware.call(self, capacity: capacity, cost: cost) do |limiter, **opts| lock = limiter.inner_limit(**opts) end if block_given? begin yield lock ensure lock.release end else lock end end
redis()
click to toggle source
# File lib/berater/limiter.rb, line 6 def redis options[:redis] || Berater.redis end
utilization()
click to toggle source
# File lib/berater/limiter.rb, line 46 def utilization lock = limit(cost: 0) if lock.capacity == 0 1.0 else lock.contention.to_f / lock.capacity end rescue Berater::Overloaded 1.0 end
Protected Instance Methods
acquire_lock(capacity, cost)
click to toggle source
# File lib/berater/limiter.rb, line 92 def acquire_lock(capacity, cost) raise NotImplementedError end
cache_key(subkey = nil)
click to toggle source
# File lib/berater/limiter.rb, line 96 def cache_key(subkey = nil) instance_key = subkey.nil? ? key : "#{key}:#{subkey}" self.class.cache_key(instance_key) end
capacity=(capacity)
click to toggle source
# File lib/berater/limiter.rb, line 78 def capacity=(capacity) unless capacity.is_a?(Numeric) raise ArgumentError, "expected Numeric, found #{capacity.class}" end if capacity == Float::INFINITY raise ArgumentError, 'infinite capacity not supported, use Unlimiter' end raise ArgumentError, 'capacity must be >= 0' unless capacity >= 0 @capacity = capacity end
inner_limit(capacity:, cost:)
click to toggle source
# File lib/berater/limiter.rb, line 29 def inner_limit(capacity:, cost:) unless capacity.is_a?(Numeric) && capacity >= 0 raise ArgumentError, "invalid capacity: #{capacity}" end unless cost.is_a?(Numeric) && cost >= 0 && cost < Float::INFINITY raise ArgumentError, "invalid cost: #{cost}" end acquire_lock(capacity, cost) rescue NoMethodError => e raise unless e.message.include?("undefined method `evalsha' for") # repackage error so it's easier to understand raise RuntimeError, "invalid redis connection: #{redis}" end