Class: Praroter::FillyBucket::Creator

Inherits:
Object
  • Object
show all
Defined in:
lib/praroter/filly_bucket/creator.rb

Constant Summary collapse

LUA_SCRIPT_CODE =
File.read(File.join(__dir__, "filly_bucket.lua"))
LUA_SCRIPT_HASH =
Digest::SHA1.hexdigest(LUA_SCRIPT_CODE)

Instance Method Summary collapse

Constructor Details

#initialize(redis:) ⇒ Creator

Returns a new instance of Creator.



8
9
10
# File 'lib/praroter/filly_bucket/creator.rb', line 8

def initialize(redis:)
  @redis = redis.respond_to?(:with) ? redis : NullPool.new(redis)
end

Instance Method Details

#run_lua_bucket_script(bucket, amount) ⇒ Object



16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/praroter/filly_bucket/creator.rb', line 16

def run_lua_bucket_script(bucket, amount)
  @redis.with do |r|
    begin
      # The script returns a tuple of "whole tokens, microtokens"
      # to be able to smuggle the float across (similar to Redis TIME command)
      new_bucket_level, bucket_capacity, fill_rate = r.evalsha(
        LUA_SCRIPT_HASH,
        keys: [bucket.level_key, bucket.last_updated_key],
        argv: [bucket.capacity, bucket.fill_rate, amount]
      )
      BucketState.new(new_bucket_level, bucket_capacity, fill_rate, amount)
    rescue Redis::CommandError => e
      if e.message.include? "NOSCRIPT"
        # The Redis server has never seen this script before. Needs to run only once in the entire lifetime
        # of the Redis server, until the script changes - in which case it will be loaded under a different SHA
        r.script(:load, LUA_SCRIPT_CODE)
        retry
      else
        raise e
      end
    end
  end
end

#setup_bucket(key:, fill_rate:, capacity:) ⇒ Object



12
13
14
# File 'lib/praroter/filly_bucket/creator.rb', line 12

def setup_bucket(key:, fill_rate:, capacity:)
  Praroter::FillyBucket::Bucket.new(key, fill_rate, capacity, self)
end