Class: Limit::BaseRateLimiter
- Inherits:
-
Object
- Object
- Limit::BaseRateLimiter
- Defined in:
- lib/limit.rb
Overview
Base Class, implementing:
-
Method to connect with redis
-
Signature for limit_calculator
Direct Known Subclasses
FixedWindowRateLimiter, RollingWindowRateLimiter, TokenBucketRateLimiter
Constant Summary collapse
- REQUIRED_KEYS =
i[max_requests window_seconds].freeze
Class Attribute Summary collapse
-
.script_sha ⇒ Object
readonly
Returns the value of attribute script_sha.
Instance Attribute Summary collapse
-
#identifier_prefix ⇒ Object
readonly
Returns the value of attribute identifier_prefix.
-
#limit_calculator ⇒ Object
readonly
Returns the value of attribute limit_calculator.
Class Method Summary collapse
Instance Method Summary collapse
- #allowed?(key) ⇒ Boolean
- #get_key(key) ⇒ Object
-
#initialize(identifier_prefix:, limit_calculator:, host: nil, port: nil, password: nil) ⇒ BaseRateLimiter
constructor
A new instance of BaseRateLimiter.
Constructor Details
#initialize(identifier_prefix:, limit_calculator:, host: nil, port: nil, password: nil) ⇒ BaseRateLimiter
Returns a new instance of BaseRateLimiter.
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/limit.rb', line 54 def initialize(identifier_prefix:, limit_calculator:, host: nil, port: nil, password: nil) # @param identifier_prefix: [String] A namespace prefix for redis keys for this limiter instance # @param limit_calculator: Lambda that takes a key(String) and returns hash: {max_requests: Integer, window_seconds: Integer} # But diff implementation can update the hash struct unless identifier_prefix.is_a?(String) && !identifier_prefix.empty? raise ArgumentError, 'identifier_prefix must be a non-empty String' end raise ArgumentError, 'limit_calculator must be a Lambda' unless limit_calculator.lambda? # Will be using the same connection across all instances unless wanted to connect to diff instance of redis @redis = if host && port && password self.class.send(:create_connection, host: host, port: port, password: password) else self.class.connection end @identifier_prefix = identifier_prefix @limit_calculator = limit_calculator @logger = self.class.logger begin @redis.ping @logger.info("Successfully connected to Redis @ #{@redis.connection[:host]}:#{@redis.connection[:port]}") rescue Redis::BaseError => e @logger.error("Error connecting to Redis: #{e.message}") raise e end self.class.load_script end |
Class Attribute Details
.script_sha ⇒ Object (readonly)
Returns the value of attribute script_sha.
39 40 41 |
# File 'lib/limit.rb', line 39 def script_sha @script_sha end |
Instance Attribute Details
#identifier_prefix ⇒ Object (readonly)
Returns the value of attribute identifier_prefix.
13 14 15 |
# File 'lib/limit.rb', line 13 def identifier_prefix @identifier_prefix end |
#limit_calculator ⇒ Object (readonly)
Returns the value of attribute limit_calculator.
13 14 15 |
# File 'lib/limit.rb', line 13 def limit_calculator @limit_calculator end |
Class Method Details
.connection ⇒ Object
22 23 24 25 26 27 |
# File 'lib/limit.rb', line 22 def connection host = ENV['REDIS_HOST'] port = ENV['REDIS_PORT'] password = ENV['REDIS_PASSWORD'] @redis ||= create_connection(host: host, port: port, password: password) end |
.load_script ⇒ Object
33 34 35 36 37 |
# File 'lib/limit.rb', line 33 def load_script script_name = name.split('::')[1].chomp('RateLimiter') script_path = File.("scripts/#{script_name}.lua", __dir__) @script_sha = @redis.script(:load, File.read(script_path)) end |
.logger ⇒ Object
29 30 31 |
# File 'lib/limit.rb', line 29 def logger @logger ||= Logger.new($stdout) end |
Instance Method Details
#allowed?(key) ⇒ Boolean
89 90 91 |
# File 'lib/limit.rb', line 89 def allowed?(key) raise NotImplementedError "#{self.class.name} must implement the allowed? method" end |
#get_key(key) ⇒ Object
93 94 95 |
# File 'lib/limit.rb', line 93 def get_key(key) "#{@identifier_prefix}:#{key}" end |