Class: Aikido::Zen::RateLimiter::Bucket

Inherits:
Object
  • Object
show all
Defined in:
lib/aikido/zen/rate_limiter/bucket.rb

Overview

This models a "sliding window" rate limiting bucket (where we keep a bucket per endpoint). The timestamps of requests are kept grouped by client, and when a new request is made, we check if the number of requests falls within the configured limit.

Examples:

bucket = Aikido::Zen::RateLimiter::Bucket.new(ttl: 60, max_size: 3)
bucket.increment("1.2.3.4") #=> true (count for this key: 1)
bucket.increment("1.2.3.4") #=> true (count for this key: 2)

# 30 seconds go by
bucket.increment("1.2.3.4") #=> true (count for this key: 3)

# 20 more seconds go by
bucket.increment("1.2.3.4") #=> false (count for this key: 3)

# 20 more seconds go by
bucket.increment("1.2.3.4") #=> true (count for this key: 2)

Instance Method Summary collapse

Constructor Details

#initialize(ttl:, max_size:, clock: DEFAULT_CLOCK, settings: nil) ⇒ Bucket



41
42
43
44
45
46
47
# File 'lib/aikido/zen/rate_limiter/bucket.rb', line 41

def initialize(ttl:, max_size:, clock: DEFAULT_CLOCK, settings: nil)
  @ttl = ttl
  @max_size = max_size
  @data = Hash.new { |h, k| h[k] = [] }
  @clock = clock
  @settings = settings
end

Instance Method Details

#increment(key) ⇒ Aikido::Zen::RateLimiter::Result

Increments the key if the number of entries within the current TTL window is below the configured threshold.



57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/aikido/zen/rate_limiter/bucket.rb', line 57

def increment(key)
  synchronize do
    time = @clock.call
    evict(key, at: time)

    entries = @data[key]
    throttled = entries.size >= @max_size

    entries << time unless throttled

    RateLimiter::Result.new(
      throttled: throttled,
      discriminator: key,
      current_requests: entries.size,
      max_requests: @max_size,
      time_remaining: @ttl - (time - entries.min)
    )
  end
end

#settings_changed?(settings) ⇒ Boolean

Checks whether the settings provided at initialization have changed.



82
83
84
# File 'lib/aikido/zen/rate_limiter/bucket.rb', line 82

def settings_changed?(settings)
  !@settings.nil? && @settings != settings
end