Class: Lutaml::Hal::RateLimiter
- Inherits:
-
Object
- Object
- Lutaml::Hal::RateLimiter
- Defined in:
- lib/lutaml/hal/rate_limiter.rb
Overview
Rate limiter to handle API rate limiting with exponential backoff
Constant Summary collapse
- DEFAULT_MAX_RETRIES =
3
- DEFAULT_BASE_DELAY =
1.0
- DEFAULT_MAX_DELAY =
60.0
- DEFAULT_BACKOFF_FACTOR =
2.0
Instance Attribute Summary collapse
-
#backoff_factor ⇒ Object
readonly
Returns the value of attribute backoff_factor.
-
#base_delay ⇒ Object
readonly
Returns the value of attribute base_delay.
-
#max_delay ⇒ Object
readonly
Returns the value of attribute max_delay.
-
#max_retries ⇒ Object
readonly
Returns the value of attribute max_retries.
Instance Method Summary collapse
-
#calculate_delay(attempt, error = nil) ⇒ Object
Calculate delay with exponential backoff.
-
#disable! ⇒ Object
Disable rate limiting.
-
#enable! ⇒ Object
Enable rate limiting.
-
#enabled? ⇒ Boolean
Check if rate limiting is enabled.
-
#extract_retry_after(response) ⇒ Object
Extract Retry-After header value.
-
#initialize(options = {}) ⇒ RateLimiter
constructor
A new instance of RateLimiter.
-
#should_retry?(error, attempt) ⇒ Boolean
Check if we should retry based on the error and attempt count.
-
#with_rate_limiting ⇒ Object
Execute a block with rate limiting and retry logic.
Constructor Details
#initialize(options = {}) ⇒ RateLimiter
14 15 16 17 18 19 20 |
# File 'lib/lutaml/hal/rate_limiter.rb', line 14 def initialize( = {}) @max_retries = [:max_retries] || DEFAULT_MAX_RETRIES @base_delay = [:base_delay] || DEFAULT_BASE_DELAY @max_delay = [:max_delay] || DEFAULT_MAX_DELAY @backoff_factor = [:backoff_factor] || DEFAULT_BACKOFF_FACTOR @enabled = [:enabled] != false # Default to enabled unless explicitly disabled end |
Instance Attribute Details
#backoff_factor ⇒ Object (readonly)
Returns the value of attribute backoff_factor.
12 13 14 |
# File 'lib/lutaml/hal/rate_limiter.rb', line 12 def backoff_factor @backoff_factor end |
#base_delay ⇒ Object (readonly)
Returns the value of attribute base_delay.
12 13 14 |
# File 'lib/lutaml/hal/rate_limiter.rb', line 12 def base_delay @base_delay end |
#max_delay ⇒ Object (readonly)
Returns the value of attribute max_delay.
12 13 14 |
# File 'lib/lutaml/hal/rate_limiter.rb', line 12 def max_delay @max_delay end |
#max_retries ⇒ Object (readonly)
Returns the value of attribute max_retries.
12 13 14 |
# File 'lib/lutaml/hal/rate_limiter.rb', line 12 def max_retries @max_retries end |
Instance Method Details
#calculate_delay(attempt, error = nil) ⇒ Object
Calculate delay with exponential backoff
55 56 57 58 59 60 61 62 63 64 65 66 67 |
# File 'lib/lutaml/hal/rate_limiter.rb', line 55 def calculate_delay(attempt, error = nil) # Check for Retry-After header if it's a rate limit error if error.is_a?(TooManyRequestsError) && error.respond_to?(:response) && error.response retry_after = extract_retry_after(error.response) return retry_after if retry_after end # Exponential backoff: base_delay * (backoff_factor ^ (attempt - 1)) delay = @base_delay * (@backoff_factor**(attempt - 1)) # Cap at max_delay [delay, @max_delay].min end |
#disable! ⇒ Object
Disable rate limiting
95 96 97 |
# File 'lib/lutaml/hal/rate_limiter.rb', line 95 def disable! @enabled = false end |
#enable! ⇒ Object
Enable rate limiting
90 91 92 |
# File 'lib/lutaml/hal/rate_limiter.rb', line 90 def enable! @enabled = true end |
#enabled? ⇒ Boolean
Check if rate limiting is enabled
100 101 102 |
# File 'lib/lutaml/hal/rate_limiter.rb', line 100 def enabled? @enabled end |
#extract_retry_after(response) ⇒ Object
Extract Retry-After header value
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/lutaml/hal/rate_limiter.rb', line 70 def extract_retry_after(response) headers = response[:headers] || {} retry_after = headers['retry-after'] || headers['Retry-After'] return nil unless retry_after # Retry-After can be in seconds (integer) or HTTP date if retry_after.match?(/^\d+$/) retry_after.to_i else # Parse HTTP date and calculate seconds from now begin retry_time = Time.parse(retry_after) [retry_time - Time.now, 0].max rescue ArgumentError nil end end end |
#should_retry?(error, attempt) ⇒ Boolean
Check if we should retry based on the error and attempt count
40 41 42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/lutaml/hal/rate_limiter.rb', line 40 def should_retry?(error, attempt) return false if attempt > @max_retries case error when TooManyRequestsError true when ServerError # Always retry on server errors true else false end end |
#with_rate_limiting ⇒ Object
Execute a block with rate limiting and retry logic
23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 |
# File 'lib/lutaml/hal/rate_limiter.rb', line 23 def with_rate_limiting return yield unless @enabled attempt = 0 begin attempt += 1 yield rescue TooManyRequestsError, ServerError => e raise unless should_retry?(e, attempt) delay = calculate_delay(attempt, e) sleep(delay) retry end end |