Class: SecApi::RateLimitTracker

Inherits:
Object
  • Object
show all
Defined in:
lib/sec_api/rate_limit_tracker.rb

Overview

Thread-safe manager for rate limit state and queue tracking.

This class provides thread-safe storage and access to rate limit information using a Mutex for synchronization. Each Client instance owns its own tracker, ensuring rate limit state is isolated per-client.

The tracker receives updates from the RateLimiter middleware and provides read access to the current state via the Client#rate_limit_state method. It also tracks the number of queued requests waiting for rate limit reset.

Examples:

Basic usage

tracker = SecApi::RateLimitTracker.new
tracker.update(limit: 100, remaining: 95, reset_at: Time.now + 60)

state = tracker.current_state
state.limit        # => 100
state.remaining    # => 95
state.available?   # => true

Thread-safe concurrent access

tracker = SecApi::RateLimitTracker.new

threads = 10.times.map do |i|
  Thread.new do
    tracker.update(limit: 100, remaining: 100 - i, reset_at: Time.now + 60)
    tracker.current_state  # Thread-safe read
  end
end
threads.each(&:join)

Per-client isolation

client1 = SecApi::Client.new
client2 = SecApi::Client.new

# Each client has independent rate limit tracking
client1.rate_limit_state  # Client 1's state
client2.rate_limit_state  # Client 2's state (independent)

See Also:

Instance Method Summary collapse

Constructor Details

#initializeRateLimitTracker

Creates a new RateLimitTracker instance.

Examples:

tracker = SecApi::RateLimitTracker.new
tracker.current_state  # => nil (no state yet)


52
53
54
55
56
# File 'lib/sec_api/rate_limit_tracker.rb', line 52

def initialize
  @mutex = Mutex.new
  @state = nil
  @queued_count = 0
end

Instance Method Details

#current_stateRateLimitState?

Returns the current rate limit state.

Returns nil if no rate limit information has been received yet. The returned RateLimitState is immutable and can be safely used outside the mutex lock.

Examples:

state = tracker.current_state
if state&.exhausted?
  # Handle rate limit exhausted
end

Returns:



95
96
97
# File 'lib/sec_api/rate_limit_tracker.rb', line 95

def current_state
  @mutex.synchronize { @state }
end

#decrement_queuedInteger

Decrements the queued request counter.

Called by the RateLimiter middleware when a request exits the queue.

Returns:

  • (Integer)

    The new queued count



148
149
150
151
152
# File 'lib/sec_api/rate_limit_tracker.rb', line 148

def decrement_queued
  @mutex.synchronize do
    @queued_count = [@queued_count - 1, 0].max
  end
end

#increment_queuedInteger

Increments the queued request counter.

Called by the RateLimiter middleware when a request enters the queue.

Returns:

  • (Integer)

    The new queued count



136
137
138
139
140
# File 'lib/sec_api/rate_limit_tracker.rb', line 136

def increment_queued
  @mutex.synchronize do
    @queued_count += 1
  end
end

#queued_countInteger

Returns the current count of queued requests.

When the rate limit is exhausted (remaining = 0), requests are queued until the rate limit resets. This method returns the current count of waiting requests.

Examples:

tracker.queued_count  # => 3 (three requests waiting)

Returns:

  • (Integer)

    Number of requests currently queued



126
127
128
# File 'lib/sec_api/rate_limit_tracker.rb', line 126

def queued_count
  @mutex.synchronize { @queued_count }
end

#reset!void

This method returns an undefined value.

Clears the current rate limit state.

After calling reset!, current_state will return nil until new rate limit headers are received.

Examples:

tracker.update(limit: 100, remaining: 0, reset_at: Time.now)
tracker.reset!
tracker.current_state  # => nil


111
112
113
# File 'lib/sec_api/rate_limit_tracker.rb', line 111

def reset!
  @mutex.synchronize { @state = nil }
end

#update(limit:, remaining:, reset_at:) ⇒ RateLimitState

Updates the rate limit state with new values.

Creates a new immutable RateLimitState object with the provided values. This method is thread-safe and can be called concurrently.

Examples:

tracker.update(limit: 100, remaining: 95, reset_at: Time.now + 60)

Parameters:

  • limit (Integer, nil)

    Total requests allowed per time window

  • remaining (Integer, nil)

    Requests remaining in current window

  • reset_at (Time, nil)

    Time when the limit resets

Returns:



71
72
73
74
75
76
77
78
79
# File 'lib/sec_api/rate_limit_tracker.rb', line 71

def update(limit:, remaining:, reset_at:)
  @mutex.synchronize do
    @state = RateLimitState.new(
      limit: limit,
      remaining: remaining,
      reset_at: reset_at
    )
  end
end