Class: BrainzLab::Utilities::RateLimiter

Inherits:
Object
  • Object
show all
Defined in:
lib/brainzlab/utilities/rate_limiter.rb

Overview

Rate limiter with support for sliding window and token bucket algorithms Integrates with Flux for metrics tracking

Examples:

Basic usage

limiter = BrainzLab::Utilities::RateLimiter.new(
  key: "api:user:123",
  limit: 100,
  window: 60  # seconds
)

if limiter.allow?
  # proceed with request
else
  # rate limited
end

With block

BrainzLab::Utilities::RateLimiter.throttle("api:user:#{user.id}", limit: 100, window: 60) do
  # this block runs only if not rate limited
end

Defined Under Namespace

Classes: MemoryStore, RedisStore

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key:, limit:, window:, store: nil) ⇒ RateLimiter

Returns a new instance of RateLimiter.



29
30
31
32
33
34
35
36
# File 'lib/brainzlab/utilities/rate_limiter.rb', line 29

def initialize(key:, limit:, window:, store: nil)
  @key = key
  @limit = limit
  @window = window
  @store = store || default_store
  @remaining = limit
  @reset_at = Time.now + window
end

Instance Attribute Details

#keyObject (readonly)

Returns the value of attribute key.



27
28
29
# File 'lib/brainzlab/utilities/rate_limiter.rb', line 27

def key
  @key
end

#limitObject (readonly)

Returns the value of attribute limit.



27
28
29
# File 'lib/brainzlab/utilities/rate_limiter.rb', line 27

def limit
  @limit
end

#remainingObject (readonly)

Returns the value of attribute remaining.



27
28
29
# File 'lib/brainzlab/utilities/rate_limiter.rb', line 27

def remaining
  @remaining
end

#reset_atObject (readonly)

Returns the value of attribute reset_at.



27
28
29
# File 'lib/brainzlab/utilities/rate_limiter.rb', line 27

def reset_at
  @reset_at
end

#windowObject (readonly)

Returns the value of attribute window.



27
28
29
# File 'lib/brainzlab/utilities/rate_limiter.rb', line 27

def window
  @window
end

Class Method Details

.allowed?(key, limit:, window:, store: nil) ⇒ Boolean

Check rate limit without incrementing

Returns:

  • (Boolean)


95
96
97
98
# File 'lib/brainzlab/utilities/rate_limiter.rb', line 95

def self.allowed?(key, limit:, window:, store: nil)
  limiter = new(key: key, limit: limit, window: window, store: store)
  limiter.allowed?
end

.throttle(key, limit:, window:, store: nil) ⇒ Object

Class method for quick throttling



83
84
85
86
87
88
89
90
91
92
# File 'lib/brainzlab/utilities/rate_limiter.rb', line 83

def self.throttle(key, limit:, window:, store: nil)
  limiter = new(key: key, limit: limit, window: window, store: store)

  if limiter.allow?
    yield if block_given?
    true
  else
    false
  end
end

Instance Method Details

#allow?Boolean

Check and consume a token

Returns:

  • (Boolean)


45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/brainzlab/utilities/rate_limiter.rb', line 45

def allow?
  count, reset = increment
  @remaining = [@limit - count, 0].max
  @reset_at = reset

  allowed = count <= @limit

  # Track metrics
  track_attempt(allowed)

  allowed
end

#allowed?Boolean

Check if request is allowed (doesn’t consume a token)

Returns:

  • (Boolean)


39
40
41
42
# File 'lib/brainzlab/utilities/rate_limiter.rb', line 39

def allowed?
  count, = get_current_count
  count < @limit
end

#reset!Object

Reset the rate limit for this key



76
77
78
79
80
# File 'lib/brainzlab/utilities/rate_limiter.rb', line 76

def reset!
  @store.delete(@key)
  @remaining = @limit
  @reset_at = Time.now + @window
end

#statusObject

Get current usage info



64
65
66
67
68
69
70
71
72
73
# File 'lib/brainzlab/utilities/rate_limiter.rb', line 64

def status
  count, reset = get_current_count
  {
    key: @key,
    limit: @limit,
    remaining: [@limit - count, 0].max,
    reset_at: reset,
    used: count
  }
end

#throttle?Boolean

Alias for allow?

Returns:

  • (Boolean)


59
60
61
# File 'lib/brainzlab/utilities/rate_limiter.rb', line 59

def throttle?
  !allow?
end