opensearch-project / opensearch-project/opensearch-ruby
Add exponential backoff to retry logic in perform_request
Nobody has claimed this yet.
- Dominant language
- Ruby
- Stars
- 114
- Forks
- 60
- PR merge metrics
- No merged PRs in 30d
Description
Problem
OpenSearch::Transport::Transport::Base#perform_request supports retry_on_failure and retry_on_status, but retries are immediate with no delay between attempts. During write saturation (e.g., bulk indexing overwhelming the write thread pool), instant retries compound the load on the cluster instead of giving it time to recover.
In our case, this caused a cascading failure: OpenSearch's write thread pool (8 threads) became saturated, clients timed out waiting for /_bulk responses, and immediate retries amplified the pressure — resulting in 69,745 HTTP 460 (client closed connection) responses in a 40-minute window.
Current behavior
# base.rb lines 305-313
rescue OpenSearch::Transport::Transport::ServerError => e
raise e unless response && @retry_on_status.include?(response.status)
log_warn "[#{e.class}] Attempt #{tries} to get response from #{url}"
if tries <= (max_retries || DEFAULT_MAX_RETRIES)
retry # <-- immediate, no delay
else
...
end
The same pattern exists for host_unreachable_exceptions (lines 314-331).
Proposed behavior
Add optional retry_backoff and retry_backoff_factor options to the transport configuration:
client = OpenSearch::Client.new(
retry_on_failure: 3,
retry_on_status: [429, 503],
retry_backoff: 1, # base delay in seconds (default: nil = no backoff)
retry_backoff_factor: 2 # exponential multiplier (default: 2)
)
When retry_backoff is set, sleep retry_backoff * (retry_backoff_factor ** (tries - 1)) seconds (with optional jitter) before each retry. This is consistent with how elasticsearch-ruby and faraday-retry handle backoff.
Workaround
We're currently monkey-patching perform_request via class_eval to inject sleep calls before each retry — this works but is fragile and version-coupled (pinned to opensearch-ruby 3.4.x).
Environment
- opensearch-ruby 3.4.0
- Ruby 3.3+
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in base.rb at OpenSearch::Transport::Transport::Base#perform_request, especially the retry branches around lines 305-331, and trace how transport configuration options are defined and passed through. Define the optional retry_backoff and retry_backoff_factor behavior for both retry paths, then verify that configured retries delay exponentially while the default remains immediate.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- ruby
- Domain
- api, backend
- Issue type
- Feature
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100