Class: Attio::RetryHandler

Inherits:
Object
  • Object
show all
Defined in:
lib/attio/retry_handler.rb

Overview

Handles automatic retry logic for failed API requests

This class implements exponential backoff retry strategy for transient errors like timeouts and rate limits.

Examples:

Using the retry handler

handler = RetryHandler.new(max_retries: 5)
handler.with_retry { api_client.get("/endpoint") }

Since:

  • 1.0.0

Constant Summary collapse

DEFAULT_MAX_RETRIES =

Since:

  • 1.0.0

3
DEFAULT_RETRY_DELAY =

seconds

Since:

  • 1.0.0

1
DEFAULT_BACKOFF_FACTOR =

Since:

  • 1.0.0

2
RETRIABLE_ERRORS =

Since:

  • 1.0.0

[
  HttpClient::TimeoutError,
  HttpClient::ConnectionError,
  ServerError,
  RateLimitError,
].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(max_retries: DEFAULT_MAX_RETRIES, retry_delay: DEFAULT_RETRY_DELAY, backoff_factor: DEFAULT_BACKOFF_FACTOR, logger: nil) ⇒ RetryHandler

Returns a new instance of RetryHandler.

Since:

  • 1.0.0



25
26
27
28
29
30
31
32
33
# File 'lib/attio/retry_handler.rb', line 25

def initialize(max_retries: DEFAULT_MAX_RETRIES,
               retry_delay: DEFAULT_RETRY_DELAY,
               backoff_factor: DEFAULT_BACKOFF_FACTOR,
               logger: nil)
  @max_retries = max_retries
  @retry_delay = retry_delay
  @backoff_factor = backoff_factor
  @logger = logger
end

Instance Attribute Details

#backoff_factorObject (readonly)

Since:

  • 1.0.0



23
24
25
# File 'lib/attio/retry_handler.rb', line 23

def backoff_factor
  @backoff_factor
end

#loggerObject (readonly)

Since:

  • 1.0.0



23
24
25
# File 'lib/attio/retry_handler.rb', line 23

def logger
  @logger
end

#max_retriesObject (readonly)

Since:

  • 1.0.0



23
24
25
# File 'lib/attio/retry_handler.rb', line 23

def max_retries
  @max_retries
end

#retry_delayObject (readonly)

Since:

  • 1.0.0



23
24
25
# File 'lib/attio/retry_handler.rb', line 23

def retry_delay
  @retry_delay
end

Instance Method Details

#log_failure(error, attempts) ⇒ Object (private)

Since:

  • 1.0.0



67
68
69
70
71
72
73
74
75
76
# File 'lib/attio/retry_handler.rb', line 67

private def log_failure(error, attempts)
  return unless logger

  logger.error(
    "Max retries exceeded",
    error: error.class.name,
    message: error.message,
    attempts: attempts
  )
end

#log_retry(error, attempt, delay) ⇒ Object (private)

Since:

  • 1.0.0



56
57
58
59
60
61
62
63
64
65
# File 'lib/attio/retry_handler.rb', line 56

private def log_retry(error, attempt, delay)
  return unless logger

  logger.warn(
    "Retry attempt #{attempt}/#{max_retries}",
    error: error.class.name,
    message: error.message,
    delay: delay
  )
end

#with_retryObject

Since:

  • 1.0.0



35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/attio/retry_handler.rb', line 35

def with_retry
  retries = 0
  delay = retry_delay

  begin
    yield
  rescue *RETRIABLE_ERRORS => e
    retries += 1

    if retries <= max_retries
      log_retry(e, retries, delay)
      sleep(delay)
      delay *= backoff_factor
      retry
    else
      log_failure(e, retries)
      raise
    end
  end
end