Class: BackgroundRetryManager

Inherits:
Object
  • Object
show all
Defined in:
lib/ibm_appconfiguration_ruby_sdk/configurations/internal/retry_manager/background_retry_manager.rb

Overview

BackgroundRetryManager

Implements exponential backoff retry strategy for long-term configuration fetch failures. This is the โ€œTier 2โ€ retry mechanism that activates after immediate retries fail.

Key Features:

  • Exponential backoff: Delays increase exponentially (2^attempt)

  • Jitter: Random delays prevent thundering herd

  • Cap: Maximum delay capped at ~1 hour

  • Thread-safe: Uses Mutex for concurrent access

  • Graceful shutdown: Properly cleans up threads

Retry Timeline Example:

Attempt 1: ~2.3 minutes
Attempt 2: ~4.7 minutes
Attempt 3: ~9.1 minutes
Attempt 4: ~18.5 minutes
Attempt 5: ~37.2 minutes
Attempt 6+: ~60 minutes (capped)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(collection_id:, environment_id:, logger: nil) ⇒ BackgroundRetryManager

Initialize the retry manager

Parameters:

  • collection_id (String)

    Collection ID for API request

  • environment_id (String)

    Environment ID for API request

  • logger (Logger) (defaults to: nil)

    Optional logger instance (creates new one if not provided)



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/ibm_appconfiguration_ruby_sdk/configurations/internal/retry_manager/background_retry_manager.rb', line 48

def initialize(collection_id:, environment_id:, logger: nil)
  @collection_id = collection_id
  @environment_id = environment_id
  @logger = logger || Logger.instance

  # Initialize ConfigFetcher
  @config_fetcher = ConfigFetcher.new(
    collection_id: collection_id,
    environment_id: environment_id,
    logger: @logger
  )

  # State management
  @active = false
  @attempt = 0
  @cap_ms = nil

  # Thread management
  @retry_thread = nil
  @mutex = Mutex.new

  @logger.info("BackgroundRetryManager initialized")
end

Instance Attribute Details

#activeObject (readonly)

Returns the value of attribute active.



41
42
43
# File 'lib/ibm_appconfiguration_ruby_sdk/configurations/internal/retry_manager/background_retry_manager.rb', line 41

def active
  @active
end

#attemptObject (readonly)

Returns the value of attribute attempt.



41
42
43
# File 'lib/ibm_appconfiguration_ruby_sdk/configurations/internal/retry_manager/background_retry_manager.rb', line 41

def attempt
  @attempt
end

Instance Method Details

#active?Boolean

Check if retry is currently active

Returns:

  • (Boolean)

    true if retry loop is running



136
137
138
# File 'lib/ibm_appconfiguration_ruby_sdk/configurations/internal/retry_manager/background_retry_manager.rb', line 136

def active?
  @mutex.synchronize { @active }
end

#current_attemptInteger

Get current attempt number

Returns:

  • (Integer)

    Current retry attempt (0-based)



143
144
145
# File 'lib/ibm_appconfiguration_ruby_sdk/configurations/internal/retry_manager/background_retry_manager.rb', line 143

def current_attempt
  @mutex.synchronize { @attempt }
end

#start(reason:) ⇒ Boolean

Start the background retry loop

This method:

  1. Checks if retry is already active (prevents duplicate retries)

  2. Initializes retry state (attempt counter, cap delay)

  3. Schedules the first retry attempt

Parameters:

  • reason (String)

    The reason for starting retry (for logging)

Returns:

  • (Boolean)

    true if started, false if already active



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
# File 'lib/ibm_appconfiguration_ruby_sdk/configurations/internal/retry_manager/background_retry_manager.rb', line 81

def start(reason:)
  # Thread-safe check and initialization
  should_start = false

  @mutex.synchronize do
    if @active
      @logger.info("โš ๏ธ  Background retry already active (attempt ##{@attempt}). Reason: #{reason}")
      return false
    end

    # Initialize retry state
    @active = true
    @attempt = 0
    @cap_ms = compute_cap_delay_ms
    should_start = true
  end

  if should_start
    cap_hours = (@cap_ms / 3_600_000.0).round(2)
    @logger.info("๐Ÿ”„ Starting background retry (cap #{cap_hours} hours). Reason: #{reason}")
    schedule_next_attempt(reason)
  end

  true
end

#stopObject

Stop the background retry loop

This method:

  1. Sets active flag to false (stops scheduling new attempts)

  2. Kills the current retry thread if running

  3. Resets all state variables

Thread-safe and idempotent (safe to call multiple times)



115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
# File 'lib/ibm_appconfiguration_ruby_sdk/configurations/internal/retry_manager/background_retry_manager.rb', line 115

def stop
  @mutex.synchronize do
    return unless @active

    @active = false
    @attempt = 0
    @cap_ms = nil
  end

  # Kill retry thread outside mutex to avoid deadlock
  if @retry_thread&.alive?
    @retry_thread.kill
    @retry_thread = nil
  end

  @logger.info("โœ“ Background retry stopped")
end