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) ⇒ Bucket

Returns a new instance of Bucket.



35
36
37
38
39
40
# File 'lib/aikido/zen/rate_limiter/bucket.rb', line 35

def initialize(ttl:, max_size:, clock: DEFAULT_CLOCK)
  @ttl = ttl
  @max_size = max_size
  @data = Hash.new { |h, k| h[k] = [] }
  @clock = clock
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:



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/aikido/zen/rate_limiter/bucket.rb', line 50

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