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

Returns a new instance of Bucket.

Parameters:

  • ttl (Integer)

    the time to live in seconds

  • max_size (Integer)

    the number of requests before throttling

  • clock (#call() => Integer) (defaults to: DEFAULT_CLOCK)

    a callable that returns the current monotonic time in seconds

  • settings (Aikido::Zen::RuntimeSettings::RateLimitSettings, nil) (defaults to: nil)

    the settings that might change



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.

Parameters:

Returns:



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.

Parameters:

Returns:

  • (Boolean)

    true if settings were provided at initialization and the settings have changed



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

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