Exception: Poodle::RateLimitError

Inherits:
Error
  • Object
show all
Defined in:
lib/poodle/errors/rate_limit_error.rb

Overview

Exception raised when API rate limits are exceeded (429 Too Many Requests)

Examples:

Handling rate limit errors

begin
  client.send_email(email)
rescue Poodle::RateLimitError => e
  puts "Rate limit exceeded: #{e.message}"
  puts "Retry after: #{e.retry_after} seconds" if e.retry_after
  puts "Limit: #{e.limit}, Remaining: #{e.remaining}"
end

Instance Attribute Summary collapse

Attributes inherited from Error

#context, #status_code

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Error

#message, #to_s

Constructor Details

#initialize(message = "Rate limit exceeded", **options) ⇒ RateLimitError

Initialize a new RateLimitError

Parameters:

  • message (String) (defaults to: "Rate limit exceeded")

    the error message

  • retry_after (Integer, nil)

    seconds to wait before retrying

  • limit (Integer, nil)

    the rate limit

  • remaining (Integer, nil)

    remaining requests

  • reset_time (Integer, nil)

    time when the rate limit resets

  • context (Hash)

    additional context information



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/poodle/errors/rate_limit_error.rb', line 37

def initialize(message = "Rate limit exceeded", **options)
  @retry_after = options[:retry_after]
  @limit = options[:limit]
  @remaining = options[:remaining]
  @reset_time = options[:reset_time]
  context = options.fetch(:context, {})

  rate_context = {
    error_type: "rate_limit_exceeded",
    retry_after: @retry_after,
    limit: @limit,
    remaining: @remaining,
    reset_time: @reset_time
  }.compact

  super(message, context: context.merge(rate_context), status_code: 429)
end

Instance Attribute Details

#limitInteger? (readonly)

Returns the rate limit.

Returns:

  • (Integer, nil)

    the rate limit



21
22
23
# File 'lib/poodle/errors/rate_limit_error.rb', line 21

def limit
  @limit
end

#remainingInteger? (readonly)

Returns remaining requests.

Returns:

  • (Integer, nil)

    remaining requests



24
25
26
# File 'lib/poodle/errors/rate_limit_error.rb', line 24

def remaining
  @remaining
end

#reset_timeInteger? (readonly)

Returns time when the rate limit resets.

Returns:

  • (Integer, nil)

    time when the rate limit resets



27
28
29
# File 'lib/poodle/errors/rate_limit_error.rb', line 27

def reset_time
  @reset_time
end

#retry_afterInteger? (readonly)

Returns seconds to wait before retrying.

Returns:

  • (Integer, nil)

    seconds to wait before retrying



18
19
20
# File 'lib/poodle/errors/rate_limit_error.rb', line 18

def retry_after
  @retry_after
end

Class Method Details

.build_context(limit, remaining, reset_time) ⇒ Hash (private)

Build context hash

Parameters:

  • limit (String, nil)

    rate limit

  • remaining (String, nil)

    remaining requests

  • reset_time (String, nil)

    reset time

Returns:

  • (Hash)

    context hash



126
127
128
129
130
131
132
# File 'lib/poodle/errors/rate_limit_error.rb', line 126

def self.build_context(limit, remaining, reset_time)
  {
    limit: limit,
    remaining: remaining,
    reset_at: reset_time
  }.compact
end

.build_message(retry_after) ⇒ String (private)

Build error message

Parameters:

  • retry_after (Integer, nil)

    retry after seconds

Returns:

  • (String)

    error message



114
115
116
117
118
# File 'lib/poodle/errors/rate_limit_error.rb', line 114

def self.build_message(retry_after)
  message = "Rate limit exceeded."
  message += " Retry after #{retry_after} seconds." if retry_after
  message
end

.extract_limit(headers) ⇒ String? (private)

Extract rate limit from headers

Parameters:

  • headers (Hash)

    HTTP response headers

Returns:

  • (String, nil)

    rate limit value



90
91
92
# File 'lib/poodle/errors/rate_limit_error.rb', line 90

def self.extract_limit(headers)
  headers["X-RateLimit-Limit"] || headers["ratelimit-limit"]
end

.extract_remaining(headers) ⇒ String? (private)

Extract remaining requests from headers

Parameters:

  • headers (Hash)

    HTTP response headers

Returns:

  • (String, nil)

    remaining requests value



98
99
100
# File 'lib/poodle/errors/rate_limit_error.rb', line 98

def self.extract_remaining(headers)
  headers["X-RateLimit-Remaining"] || headers["ratelimit-remaining"]
end

.extract_reset_time(headers) ⇒ String? (private)

Extract reset time from headers

Parameters:

  • headers (Hash)

    HTTP response headers

Returns:

  • (String, nil)

    reset time value



106
107
108
# File 'lib/poodle/errors/rate_limit_error.rb', line 106

def self.extract_reset_time(headers)
  headers["X-RateLimit-Reset"] || headers["ratelimit-reset"]
end

.extract_retry_after(headers) ⇒ Integer? (private)

Extract retry-after value from headers

Parameters:

  • headers (Hash)

    HTTP response headers

Returns:

  • (Integer, nil)

    retry after seconds



82
83
84
# File 'lib/poodle/errors/rate_limit_error.rb', line 82

def self.extract_retry_after(headers)
  headers["retry-after"]&.to_i
end

.from_headers(headers) ⇒ RateLimitError

Create a RateLimitError from response headers

Parameters:

  • headers (Hash)

    HTTP response headers

Returns:



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/poodle/errors/rate_limit_error.rb', line 59

def self.from_headers(headers)
  retry_after = extract_retry_after(headers)
  limit = extract_limit(headers)
  remaining = extract_remaining(headers)
  reset_time = extract_reset_time(headers)

  message = build_message(retry_after)
  context = build_context(limit, remaining, reset_time)

  new(
    message,
    retry_after: retry_after,
    limit: limit&.to_i,
    remaining: remaining&.to_i,
    reset_time: reset_time&.to_i,
    context: context
  )
end

Instance Method Details

#reset_atTime?

Get the time when the rate limit resets as a Time object

Returns:

  • (Time, nil)

    the reset time



140
141
142
143
144
# File 'lib/poodle/errors/rate_limit_error.rb', line 140

def reset_at
  return nil unless @reset_time

  Time.at(@reset_time)
end