Class: Complyance::RetryStrategy
- Inherits:
-
Object
- Object
- Complyance::RetryStrategy
- Defined in:
- lib/complyance/retry_strategy.rb
Overview
Advanced retry strategy with exponential backoff, jitter, and circuit breaker
Instance Method Summary collapse
-
#circuit_breaker_state ⇒ String?
Get the current circuit breaker state (for monitoring).
-
#circuit_breaker_stats ⇒ String
Get circuit breaker statistics (for monitoring).
-
#execute(operation_name, &operation) ⇒ Object
Execute a function with retry logic.
-
#initialize(config = {}) ⇒ RetryStrategy
constructor
Initialize retry strategy.
Constructor Details
#initialize(config = {}) ⇒ RetryStrategy
Initialize retry strategy
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/complyance/retry_strategy.rb', line 20 def initialize(config = {}) @config = { max_attempts: 3, base_delay: 1000, max_delay: 30000, backoff_multiplier: 2.0, jitter_factor: 0.2, retryable_errors: ['RATE_LIMIT_EXCEEDED', 'SERVICE_UNAVAILABLE'], retryable_http_codes: [408, 429, 500, 502, 503, 504], circuit_breaker_enabled: true, circuit_breaker_config: { failure_threshold: 3, reset_timeout: 60 } }.merge(config) @logger = Logger.new(STDOUT) @logger.level = Logger::INFO if @config[:circuit_breaker_enabled] @circuit_breaker = CircuitBreaker.new(@config[:circuit_breaker_config]) end end |
Instance Method Details
#circuit_breaker_state ⇒ String?
Get the current circuit breaker state (for monitoring)
123 124 125 |
# File 'lib/complyance/retry_strategy.rb', line 123 def circuit_breaker_state @circuit_breaker&.state end |
#circuit_breaker_stats ⇒ String
Get circuit breaker statistics (for monitoring)
129 130 131 132 133 134 135 136 |
# File 'lib/complyance/retry_strategy.rb', line 129 def circuit_breaker_stats if @circuit_breaker "CircuitBreaker{state=#{@circuit_breaker.state}, failures=#{@circuit_breaker.failure_count}, " \ "lastFailure=#{@circuit_breaker.last_failure_time}}" else "Circuit breaker disabled" end end |
#execute(operation_name, &operation) ⇒ Object
Execute a function with retry logic
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
# File 'lib/complyance/retry_strategy.rb', line 49 def execute(operation_name, &operation) attempt = 1 last_exception = nil while attempt <= @config[:max_attempts] begin @logger.debug "Attempting operation '#{operation_name}' (attempt #{attempt}/#{@config[:max_attempts]})" # Use circuit breaker if enabled result = if @circuit_breaker begin @circuit_breaker.execute(&operation) rescue RuntimeError => e if e..include?('Circuit breaker is open') raise SDKException.new(ErrorDetail.new( 'CIRCUIT_BREAKER_OPEN', e. )) end raise e end else operation.call end if attempt > 1 @logger.info "Operation '#{operation_name}' succeeded on attempt #{attempt}" end return result rescue SDKException => e last_exception = e # Check if this error should be retried unless should_retry?(e, attempt) @logger.debug "Operation '#{operation_name}' failed with non-retryable error: #{e.}" raise e end # If this was the last attempt, don't wait break if attempt >= @config[:max_attempts] # Calculate delay and wait delay = calculate_delay(attempt) @logger.warn "Operation '#{operation_name}' failed on attempt #{attempt} (#{e.}), retrying in #{delay}ms" sleep(delay / 1000.0) # Convert ms to seconds rescue StandardError => e @logger.error "Unexpected error in operation '#{operation_name}': #{e.}" error = ErrorDetail.new( 'PROCESSING_ERROR', "Unexpected error: #{e.}" ) error.suggestion = "This appears to be an unexpected error. Please contact support if it persists" error.add_context_value('originalException', e.class.name) raise SDKException.new(error) end attempt += 1 end # All retries exhausted @logger.error "Operation '#{operation_name}' failed after #{@config[:max_attempts]} attempts" raise last_exception || SDKException.new(ErrorDetail.new( 'MAX_RETRIES_EXCEEDED', "Maximum retry attempts (#{@config[:max_attempts]}) exceeded" )) end |