Class: Lutaml::Hal::RateLimiter

Inherits:
Object
  • Object
show all
Defined in:
lib/lutaml/hal/rate_limiter.rb

Constant Summary collapse

DEFAULT_MAX_RETRIES =
5
DEFAULT_BASE_DELAY =
0.05
DEFAULT_MAX_DELAY =
5.0
DEFAULT_BACKOFF_FACTOR =
1.5

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ RateLimiter

Returns a new instance of RateLimiter.



13
14
15
16
17
18
19
# File 'lib/lutaml/hal/rate_limiter.rb', line 13

def initialize(options = {})
  @max_retries = options[:max_retries] || DEFAULT_MAX_RETRIES
  @base_delay = options[:base_delay] || DEFAULT_BASE_DELAY
  @max_delay = options[:max_delay] || DEFAULT_MAX_DELAY
  @backoff_factor = options[:backoff_factor] || DEFAULT_BACKOFF_FACTOR
  @enabled = options[:enabled] != false
end

Instance Attribute Details

#backoff_factorObject (readonly)

Returns the value of attribute backoff_factor.



11
12
13
# File 'lib/lutaml/hal/rate_limiter.rb', line 11

def backoff_factor
  @backoff_factor
end

#base_delayObject (readonly)

Returns the value of attribute base_delay.



11
12
13
# File 'lib/lutaml/hal/rate_limiter.rb', line 11

def base_delay
  @base_delay
end

#max_delayObject (readonly)

Returns the value of attribute max_delay.



11
12
13
# File 'lib/lutaml/hal/rate_limiter.rb', line 11

def max_delay
  @max_delay
end

#max_retriesObject (readonly)

Returns the value of attribute max_retries.



11
12
13
# File 'lib/lutaml/hal/rate_limiter.rb', line 11

def max_retries
  @max_retries
end

Instance Method Details

#calculate_delay(attempt, error = nil) ⇒ Object



43
44
45
46
47
48
# File 'lib/lutaml/hal/rate_limiter.rb', line 43

def calculate_delay(attempt, error = nil)
  return retry_after_from_error(error) if error.is_a?(TooManyRequestsError) && retry_after_from_error(error)

  delay = @base_delay * (@backoff_factor**(attempt - 1))
  [delay, @max_delay].min
end

#disable!Object



71
72
73
# File 'lib/lutaml/hal/rate_limiter.rb', line 71

def disable!
  @enabled = false
end

#enable!Object



67
68
69
# File 'lib/lutaml/hal/rate_limiter.rb', line 67

def enable!
  @enabled = true
end

#enabled?Boolean

Returns:

  • (Boolean)


75
76
77
# File 'lib/lutaml/hal/rate_limiter.rb', line 75

def enabled?
  @enabled
end

#extract_retry_after(response) ⇒ Object



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/lutaml/hal/rate_limiter.rb', line 50

def extract_retry_after(response)
  headers = response[:headers] || {}
  retry_after = headers['retry-after'] || headers['Retry-After']
  return nil unless retry_after

  if retry_after.match?(/^\d+$/)
    retry_after.to_i
  else
    begin
      retry_time = Time.parse(retry_after)
      [retry_time - Time.now, 0].max
    rescue ArgumentError
      nil
    end
  end
end

#should_retry?(error, attempt) ⇒ Boolean

Returns:

  • (Boolean)


37
38
39
40
41
# File 'lib/lutaml/hal/rate_limiter.rb', line 37

def should_retry?(error, attempt)
  return false if attempt > @max_retries

  error.is_a?(TooManyRequestsError) || error.is_a?(ServerError)
end

#with_rate_limitingObject



21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/lutaml/hal/rate_limiter.rb', line 21

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