Skip to content

Commit 68350f9

Browse files
estolfopicandocodigo
authored andcommitted
[CLIENT] Accept options passed to #perform_request to avoid infinite retry loop
1 parent 50fe2a3 commit 68350f9

File tree

6 files changed

+199
-12
lines changed

6 files changed

+199
-12
lines changed

elasticsearch-transport/lib/elasticsearch/transport/transport/base.rb

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ module Base
1616
attr_reader :hosts, :options, :connections, :counter, :last_request_at, :protocol
1717
attr_accessor :serializer, :sniffer, :logger, :tracer,
1818
:reload_connections, :reload_after,
19-
:resurrect_after, :max_retries
19+
:resurrect_after
2020

2121
# Creates a new transport object
2222
#
@@ -52,7 +52,6 @@ def initialize(arguments={}, &block)
5252
@reload_connections = options[:reload_connections]
5353
@reload_after = options[:reload_connections].is_a?(Integer) ? options[:reload_connections] : DEFAULT_RELOAD_AFTER
5454
@resurrect_after = options[:resurrect_after] || DEFAULT_RESURRECT_AFTER
55-
@max_retries = options[:retry_on_failure].is_a?(Integer) ? options[:retry_on_failure] : DEFAULT_MAX_RETRIES
5655
@retry_on_status = Array(options[:retry_on_status]).map { |d| d.to_i }
5756
end
5857

@@ -244,10 +243,17 @@ def __full_url(host)
244243
# @raise [ServerError] If request failed on server
245244
# @raise [Error] If no connection is available
246245
#
247-
def perform_request(method, path, params={}, body=nil, headers=nil, &block)
246+
def perform_request(method, path, params={}, body=nil, headers=nil, opts={}, &block)
248247
raise NoMethodError, "Implement this method in your transport class" unless block_given?
249248
start = Time.now if logger || tracer
250249
tries = 0
250+
reload_on_failure = opts.fetch(:reload_on_failure, @options[:reload_on_failure])
251+
252+
max_retries = if opts.key?(:retry_on_failure)
253+
opts[:retry_on_failure] === true ? DEFAULT_MAX_RETRIES : opts[:retry_on_failure]
254+
elsif options.key?(:retry_on_failure)
255+
options[:retry_on_failure] === true ? DEFAULT_MAX_RETRIES : options[:retry_on_failure]
256+
end
251257

252258
params = params.clone
253259

@@ -271,9 +277,9 @@ def perform_request(method, path, params={}, body=nil, headers=nil, &block)
271277
__raise_transport_error(response) if response.status.to_i >= 300 && @retry_on_status.include?(response.status.to_i)
272278

273279
rescue Elasticsearch::Transport::Transport::ServerError => e
274-
if @retry_on_status.include?(response.status)
280+
if response && @retry_on_status.include?(response.status)
275281
logger.warn "[#{e.class}] Attempt #{tries} to get response from #{url}" if logger
276-
if tries <= max_retries
282+
if tries <= (max_retries || DEFAULT_MAX_RETRIES)
277283
retry
278284
else
279285
logger.fatal "[#{e.class}] Cannot get response from #{url} after #{tries} tries" if logger
@@ -288,12 +294,12 @@ def perform_request(method, path, params={}, body=nil, headers=nil, &block)
288294

289295
connection.dead!
290296

291-
if @options[:reload_on_failure] and tries < connections.all.size
297+
if reload_on_failure and tries < connections.all.size
292298
logger.warn "[#{e.class}] Reloading connections (attempt #{tries} of #{connections.all.size})" if logger
293299
reload_connections! and retry
294300
end
295301

296-
if @options[:retry_on_failure]
302+
if max_retries
297303
logger.warn "[#{e.class}] Attempt #{tries} connecting to #{connection.host.inspect}" if logger
298304
if tries <= max_retries
299305
retry

elasticsearch-transport/lib/elasticsearch/transport/transport/http/curb.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ class Curb
1515
# @return [Response]
1616
# @see Transport::Base#perform_request
1717
#
18-
def perform_request(method, path, params={}, body=nil, headers=nil)
19-
super do |connection,url|
18+
def perform_request(method, path, params={}, body=nil, headers=nil, opts={})
19+
super do |connection, url|
2020
connection.connection.url = url
2121

2222
case method

elasticsearch-transport/lib/elasticsearch/transport/transport/http/faraday.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ class Faraday
1616
# @return [Response]
1717
# @see Transport::Base#perform_request
1818
#
19-
def perform_request(method, path, params={}, body=nil, headers=nil)
19+
def perform_request(method, path, params={}, body=nil, headers=nil, opts={})
2020
super do |connection, url|
2121
headers = headers || connection.connection.headers
2222

elasticsearch-transport/lib/elasticsearch/transport/transport/http/manticore.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ def build_client(options={})
6363
# @return [Response]
6464
# @see Transport::Base#perform_request
6565
#
66-
def perform_request(method, path, params={}, body=nil, headers=nil)
66+
def perform_request(method, path, params={}, body=nil, headers=nil, opts={})
6767
super do |connection, url|
6868
params[:body] = __convert_to_json(body) if body
6969
params[:headers] = headers if headers

elasticsearch-transport/lib/elasticsearch/transport/transport/sniffer.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ def initialize(transport)
2828
#
2929
def hosts
3030
Timeout::timeout(timeout, SnifferTimeoutError) do
31-
nodes = transport.perform_request('GET', '_nodes/http').body
31+
nodes = transport.perform_request('GET', '_nodes/http', {}, nil, nil,
32+
reload_on_failure: false).body
3233

3334
hosts = nodes['nodes'].map do |id,info|
3435
if info[PROTOCOL]

elasticsearch-transport/spec/elasticsearch/transport/base_spec.rb

Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,4 +73,184 @@
7373
it_behaves_like 'a redacted string'
7474
end
7575
end
76+
77+
context 'when reload_on_failure is true and and hosts are unreachable' do
78+
79+
let(:client) do
80+
Elasticsearch::Transport::Client.new(arguments)
81+
end
82+
83+
let(:arguments) do
84+
{
85+
hosts: ['http://unavabilable:9200', 'http://unavabilable:9201'],
86+
reload_on_failure: true,
87+
sniffer_timeout: 5
88+
}
89+
end
90+
91+
it 'raises an exception' do
92+
expect {
93+
client.info
94+
}.to raise_exception(Faraday::ConnectionFailed)
95+
end
96+
end
97+
98+
context 'when the client has `retry_on_failure` set to an integer' do
99+
100+
let(:client) do
101+
Elasticsearch::Transport::Client.new(arguments)
102+
end
103+
104+
let(:arguments) do
105+
{
106+
hosts: ['http://unavabilable:9200', 'http://unavabilable:9201'],
107+
retry_on_failure: 2
108+
}
109+
end
110+
111+
context 'when `perform_request` is called without a `retry_on_failure` option value' do
112+
113+
before do
114+
expect(client.transport).to receive(:get_connection).exactly(3).times.and_call_original
115+
end
116+
117+
it 'uses the client `retry_on_failure` value' do
118+
expect {
119+
client.transport.perform_request('GET', '/info')
120+
}.to raise_exception(Faraday::ConnectionFailed)
121+
end
122+
end
123+
124+
context 'when `perform_request` is called with a `retry_on_failure` option value' do
125+
126+
before do
127+
expect(client.transport).to receive(:get_connection).exactly(6).times.and_call_original
128+
end
129+
130+
it 'uses the option `retry_on_failure` value' do
131+
expect {
132+
client.transport.perform_request('GET', '/info', {}, nil, nil, retry_on_failure: 5)
133+
}.to raise_exception(Faraday::ConnectionFailed)
134+
end
135+
end
136+
end
137+
138+
context 'when the client has `retry_on_failure` set to true' do
139+
140+
let(:client) do
141+
Elasticsearch::Transport::Client.new(arguments)
142+
end
143+
144+
let(:arguments) do
145+
{
146+
hosts: ['http://unavabilable:9200', 'http://unavabilable:9201'],
147+
retry_on_failure: true
148+
}
149+
end
150+
151+
context 'when `perform_request` is called without a `retry_on_failure` option value' do
152+
153+
before do
154+
expect(client.transport).to receive(:get_connection).exactly(4).times.and_call_original
155+
end
156+
157+
it 'uses the default `MAX_RETRIES` value' do
158+
expect {
159+
client.transport.perform_request('GET', '/info')
160+
}.to raise_exception(Faraday::ConnectionFailed)
161+
end
162+
end
163+
164+
context 'when `perform_request` is called with a `retry_on_failure` option value' do
165+
166+
before do
167+
expect(client.transport).to receive(:get_connection).exactly(6).times.and_call_original
168+
end
169+
170+
it 'uses the option `retry_on_failure` value' do
171+
expect {
172+
client.transport.perform_request('GET', '/info', {}, nil, nil, retry_on_failure: 5)
173+
}.to raise_exception(Faraday::ConnectionFailed)
174+
end
175+
end
176+
end
177+
178+
context 'when the client has `retry_on_failure` set to false' do
179+
180+
let(:client) do
181+
Elasticsearch::Transport::Client.new(arguments)
182+
end
183+
184+
let(:arguments) do
185+
{
186+
hosts: ['http://unavabilable:9200', 'http://unavabilable:9201'],
187+
retry_on_failure: false
188+
}
189+
end
190+
191+
context 'when `perform_request` is called without a `retry_on_failure` option value' do
192+
193+
before do
194+
expect(client.transport).to receive(:get_connection).once.and_call_original
195+
end
196+
197+
it 'does not retry' do
198+
expect {
199+
client.transport.perform_request('GET', '/info')
200+
}.to raise_exception(Faraday::ConnectionFailed)
201+
end
202+
end
203+
204+
context 'when `perform_request` is called with a `retry_on_failure` option value' do
205+
206+
before do
207+
expect(client.transport).to receive(:get_connection).exactly(6).times.and_call_original
208+
end
209+
210+
it 'uses the option `retry_on_failure` value' do
211+
expect {
212+
client.transport.perform_request('GET', '/info', {}, nil, nil, retry_on_failure: 5)
213+
}.to raise_exception(Faraday::ConnectionFailed)
214+
end
215+
end
216+
end
217+
218+
context 'when the client has no `retry_on_failure` set' do
219+
220+
let(:client) do
221+
Elasticsearch::Transport::Client.new(arguments)
222+
end
223+
224+
let(:arguments) do
225+
{
226+
hosts: ['http://unavabilable:9200', 'http://unavabilable:9201'],
227+
}
228+
end
229+
230+
context 'when `perform_request` is called without a `retry_on_failure` option value' do
231+
232+
before do
233+
expect(client.transport).to receive(:get_connection).exactly(1).times.and_call_original
234+
end
235+
236+
it 'does not retry' do
237+
expect {
238+
client.transport.perform_request('GET', '/info')
239+
}.to raise_exception(Faraday::ConnectionFailed)
240+
end
241+
end
242+
243+
context 'when `perform_request` is called with a `retry_on_failure` option value' do
244+
245+
before do
246+
expect(client.transport).to receive(:get_connection).exactly(6).times.and_call_original
247+
end
248+
249+
it 'uses the option `retry_on_failure` value' do
250+
expect {
251+
client.transport.perform_request('GET', '/info', {}, nil, nil, retry_on_failure: 5)
252+
}.to raise_exception(Faraday::ConnectionFailed)
253+
end
254+
end
255+
end
76256
end

0 commit comments

Comments
 (0)