elasticsearch-transport 1.0.14 → 1.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a1c41acb9864d25738a29b7ced81856e5eea8660
4
- data.tar.gz: 1675e534fedd834b107e51c620767f11e1b9327f
3
+ metadata.gz: c8912230f142b53ab174f9cb27d98c3faa220517
4
+ data.tar.gz: d561830a59e77b6daf839a4b7fef09394506ea98
5
5
  SHA512:
6
- metadata.gz: 2473aa1f15584614fcf9c96e75030bd37979817ba4ddcce78134781b275deedd35cf1a62a46af649c704d2d84a247751fe680be1c111de8ac8d25e6c33316817
7
- data.tar.gz: 18aa296103d2c29b5ae11a3258f7e9c5f97c6787ad061ad4d0713a9e7fb916d920fb0c92604065bbbedf6fd7e15f75d2a253238a7cb26de141e7c48f0727f616
6
+ metadata.gz: 6a41d9e20a098bb9731e7029daf96996c92e898b982fef262ac290cd680dde7a5d99d8d6134aaca5c9a1df31dc525aeee603e0881d80ae972315b7524579e7e6
7
+ data.tar.gz: 83667f70dc3c27c925f63ec0def5400f292f60bfe4b9b83629c74a243adb8a0dd23ecd45dd247c9530da06bb7429411cddc10355b00c40a1e64e6250c21e9062
data/README.md CHANGED
@@ -271,24 +271,6 @@ To use a specific adapter for _Faraday_, pass it as the `adapter` argument:
271
271
  client.transport.connections.first.connection.builder.handlers
272
272
  # => [Faraday::Adapter::NetHttpPersistent]
273
273
 
274
- To configure the _Faraday_ instance, pass a configuration block to the transport constructor:
275
-
276
- require 'typhoeus'
277
- require 'typhoeus/adapters/faraday'
278
-
279
- transport_configuration = lambda do |f|
280
- f.response :logger
281
- f.adapter :typhoeus
282
- end
283
-
284
- transport = Elasticsearch::Transport::Transport::HTTP::Faraday.new \
285
- hosts: [ { host: 'localhost', port: '9200' } ],
286
- &transport_configuration
287
-
288
- # Pass the transport to the client
289
- #
290
- client = Elasticsearch::Client.new transport: transport
291
-
292
274
  To pass options to the
293
275
  [`Faraday::Connection`](https://github.com/lostisland/faraday/blob/master/lib/faraday/connection.rb)
294
276
  constructor, use the `transport_options` key:
@@ -300,23 +282,46 @@ constructor, use the `transport_options` key:
300
282
  ssl: { verify: false }
301
283
  }
302
284
 
303
- You can also use a bundled [_Curb_](https://rubygems.org/gems/curb) based transport implementation:
285
+ To configure the _Faraday_ instance directly, use a block:
304
286
 
305
- require 'curb'
306
- require 'elasticsearch/transport/transport/http/curb'
287
+ require 'typhoeus'
288
+ require 'typhoeus/adapters/faraday'
307
289
 
308
- client = Elasticsearch::Client.new transport_class: Elasticsearch::Transport::Transport::HTTP::Curb
290
+ client = Elasticsearch::Client.new(host: 'localhost', port: '9200') do |f|
291
+ f.response :logger
292
+ f.adapter :typhoeus
293
+ end
309
294
 
310
- client.transport.connections.first.connection
311
- # => #<Curl::Easy http://localhost:9200/>
295
+ You can use any standard Faraday middleware and plugins in the configuration block,
296
+ for example sign the requests for the [AWS Elasticsearch service](https://aws.amazon.com/elasticsearch-service/):
312
297
 
313
- It's possible to customize the _Curb_ instance by passing a block to the constructor as well
314
- (in this case, as an inline block):
298
+ require 'patron'
299
+ require 'faraday_middleware/aws_signers_v4'
315
300
 
316
- transport = Elasticsearch::Transport::Transport::HTTP::Curb.new \
301
+ client = Elasticsearch::Client.new url: 'https://search-my-cluster-abc123....es.amazonaws.com' do |f|
302
+ f.request :aws_signers_v4,
303
+ credentials: Aws::Credentials.new(ENV['AWS_ACCESS_KEY'], ENV['AWS_SECRET_ACCESS_KEY']),
304
+ service_name: 'es',
305
+ region: 'us-east-1'
306
+ end
307
+
308
+ You can also initialize the transport class yourself, and pass it to the client constructor
309
+ as the `transport` argument:
310
+
311
+ require 'typhoeus'
312
+ require 'typhoeus/adapters/faraday'
313
+
314
+ transport_configuration = lambda do |f|
315
+ f.response :logger
316
+ f.adapter :typhoeus
317
+ end
318
+
319
+ transport = Elasticsearch::Transport::Transport::HTTP::Faraday.new \
317
320
  hosts: [ { host: 'localhost', port: '9200' } ],
318
- & lambda { |c| c.verbose = true }
321
+ &transport_configuration
319
322
 
323
+ # Pass the transport to the client
324
+ #
320
325
  client = Elasticsearch::Client.new transport: transport
321
326
 
322
327
  Instead of passing the transport to the constructor, you can inject it at run time:
@@ -345,6 +350,25 @@ Instead of passing the transport to the constructor, you can inject it at run ti
345
350
  #
346
351
  client.transport = faraday_client
347
352
 
353
+ You can also use a bundled [_Curb_](https://rubygems.org/gems/curb) based transport implementation:
354
+
355
+ require 'curb'
356
+ require 'elasticsearch/transport/transport/http/curb'
357
+
358
+ client = Elasticsearch::Client.new transport_class: Elasticsearch::Transport::Transport::HTTP::Curb
359
+
360
+ client.transport.connections.first.connection
361
+ # => #<Curl::Easy http://localhost:9200/>
362
+
363
+ It's possible to customize the _Curb_ instance by passing a block to the constructor as well
364
+ (in this case, as an inline block):
365
+
366
+ transport = Elasticsearch::Transport::Transport::HTTP::Curb.new \
367
+ hosts: [ { host: 'localhost', port: '9200' } ],
368
+ & lambda { |c| c.verbose = true }
369
+
370
+ client = Elasticsearch::Client.new transport: transport
371
+
348
372
  You can write your own transport implementation easily, by including the
349
373
  {Elasticsearch::Transport::Transport::Base} module, implementing the required contract,
350
374
  and passing it to the client as the `transport_class` parameter -- or injecting it directly.
@@ -46,6 +46,7 @@ Gem::Specification.new do |s|
46
46
  s.add_development_dependency "curb" unless defined? JRUBY_VERSION
47
47
  s.add_development_dependency "patron" unless defined? JRUBY_VERSION
48
48
  s.add_development_dependency "typhoeus", '~> 0.6'
49
+ s.add_development_dependency "net-http-persistent"
49
50
  s.add_development_dependency "manticore", '~> 0.3.5' if defined? JRUBY_VERSION
50
51
  s.add_development_dependency "hashie"
51
52
 
@@ -22,8 +22,8 @@ module Elasticsearch
22
22
 
23
23
  # A convenience wrapper for {::Elasticsearch::Transport::Client#initialize}.
24
24
  #
25
- def new(arguments={})
26
- Elasticsearch::Transport::Client.new(arguments)
25
+ def new(arguments={}, &block)
26
+ Elasticsearch::Transport::Client.new(arguments, &block)
27
27
  end
28
28
  extend self
29
29
  end
@@ -56,6 +56,7 @@ module Elasticsearch
56
56
  #
57
57
  # @option arguments [Boolean,Number] :retry_on_failure Retry X times when request fails before raising and
58
58
  # exception (false by default)
59
+ # @option arguments Array<Number> :retry_on_status Retry when specific status codes are returned
59
60
  #
60
61
  # @option arguments [Boolean] :reload_on_failure Reload connections after failure (false by default)
61
62
  #
@@ -79,7 +80,9 @@ module Elasticsearch
79
80
  # @option arguments [String] :send_get_body_as Specify the HTTP method to use for GET requests with a body.
80
81
  # (Default: GET)
81
82
  #
82
- def initialize(arguments={})
83
+ # @yield [faraday] Access and configure the `Faraday::Connection` instance directly with a block
84
+ #
85
+ def initialize(arguments={}, &block)
83
86
  hosts = arguments[:hosts] || \
84
87
  arguments[:host] || \
85
88
  arguments[:url] || \
@@ -103,7 +106,10 @@ module Elasticsearch
103
106
  @transport = arguments[:transport] || begin
104
107
  if transport_class == Transport::HTTP::Faraday
105
108
  transport_class.new(:hosts => __extract_hosts(hosts, arguments), :options => arguments) do |faraday|
106
- faraday.adapter(arguments[:adapter] || __auto_detect_adapter)
109
+ block.call faraday if block
110
+ unless (h = faraday.builder.handlers.last) && h.name.start_with?("Faraday::Adapter")
111
+ faraday.adapter(arguments[:adapter] || __auto_detect_adapter)
112
+ end
107
113
  end
108
114
  else
109
115
  transport_class.new(:hosts => __extract_hosts(hosts, arguments), :options => arguments)
@@ -47,6 +47,7 @@ module Elasticsearch
47
47
  @reload_after = options[:reload_connections].is_a?(Fixnum) ? options[:reload_connections] : DEFAULT_RELOAD_AFTER
48
48
  @resurrect_after = options[:resurrect_after] || DEFAULT_RESURRECT_AFTER
49
49
  @max_retries = options[:retry_on_failure].is_a?(Fixnum) ? options[:retry_on_failure] : DEFAULT_MAX_RETRIES
50
+ @retry_on_status = Array(options[:retry_on_status]).map { |d| d.to_i }
50
51
  end
51
52
 
52
53
  # Returns a connection from the connection pool by delegating to {Connections::Collection#get_connection}.
@@ -95,9 +96,18 @@ module Elasticsearch
95
96
  def __rebuild_connections(arguments={})
96
97
  @hosts = arguments[:hosts] || []
97
98
  @options = arguments[:options] || {}
99
+ __close_connections
98
100
  @connections = __build_connections
99
101
  end
100
102
 
103
+ # Closes the connections collection.
104
+ #
105
+ # @api private
106
+ #
107
+ def __close_connections
108
+ # to be implemented by specific transports
109
+ end
110
+
101
111
  # Log request and response information.
102
112
  #
103
113
  # @api private
@@ -192,6 +202,23 @@ module Elasticsearch
192
202
 
193
203
  connection.healthy! if connection.failures > 0
194
204
 
205
+ # Raise an exception so we can catch it for `retry_on_status`
206
+ __raise_transport_error(response) if response.status.to_i >= 300 && @retry_on_status.include?(response.status.to_i)
207
+
208
+ rescue Elasticsearch::Transport::Transport::ServerError => e
209
+ if @retry_on_status.include?(response.status)
210
+ logger.warn "[#{e.class}] Attempt #{tries} to get response from #{url}" if logger
211
+ logger.debug "[#{e.class}] Attempt #{tries} to get response from #{url}" if logger
212
+ if tries <= max_retries
213
+ retry
214
+ else
215
+ logger.fatal "[#{e.class}] Cannot get response from #{url} after #{tries} tries" if logger
216
+ raise e
217
+ end
218
+ else
219
+ raise e
220
+ end
221
+
195
222
  rescue *host_unreachable_exceptions => e
196
223
  logger.error "[#{e.class}] #{e.message} #{connection.host.inspect}" if logger
197
224
 
@@ -217,7 +244,8 @@ module Elasticsearch
217
244
  rescue Exception => e
218
245
  logger.fatal "[#{e.class}] #{e.message} (#{connection.host.inspect if connection})" if logger
219
246
  raise e
220
- end
247
+
248
+ end #/begin
221
249
 
222
250
  duration = Time.now-start if logger || tracer
223
251
 
@@ -105,6 +105,16 @@ module Elasticsearch
105
105
  :selector => options[:selector]
106
106
  end
107
107
 
108
+ # Closes all connections by marking them as dead
109
+ # and closing the underlying HttpClient instances
110
+ #
111
+ # @return [Connections::Collection]
112
+ #
113
+ def __close_connections
114
+ @connections.each {|c| c.dead! }
115
+ @connections.all.each {|c| c.connection.close }
116
+ end
117
+
108
118
  # Returns an array of implementation specific connection errors.
109
119
  #
110
120
  # @return [Array]
@@ -1,5 +1,5 @@
1
1
  module Elasticsearch
2
2
  module Transport
3
- VERSION = "1.0.14"
3
+ VERSION = "1.0.15"
4
4
  end
5
5
  end
@@ -11,8 +11,9 @@ class Elasticsearch::Transport::ClientIntegrationTest < Elasticsearch::Test::Int
11
11
 
12
12
  context "Elasticsearch client" do
13
13
  teardown do
14
- begin; Object.send(:remove_const, :Typhoeus); rescue NameError; end
15
- begin; Object.send(:remove_const, :Patron); rescue NameError; end
14
+ begin; Object.send(:remove_const, :Typhoeus); rescue NameError; end
15
+ begin; Object.send(:remove_const, :Patron); rescue NameError; end
16
+ begin; Net::HTTP.send(:remove_const, :Persistent); rescue NameError; end
16
17
  end
17
18
 
18
19
  setup do
@@ -63,6 +64,20 @@ class Elasticsearch::Transport::ClientIntegrationTest < Elasticsearch::Test::Int
63
64
  assert_match /---\ncluster_name:/, response.body.to_s
64
65
  end
65
66
 
67
+ should "pass options to the Faraday::Connection with a block" do
68
+ @client = Elasticsearch::Client.new(
69
+ host: "localhost:#{@port}",
70
+ logger: (ENV['QUIET'] ? nil : @logger)
71
+ ) do |client|
72
+ client.headers['Content-Type'] = 'application/yaml'
73
+ end
74
+
75
+ response = @client.perform_request 'GET', '_cluster/health'
76
+
77
+ assert response.body.start_with?("---\n"), "Response body should be YAML: #{response.body.inspect}"
78
+ assert_equal 'application/yaml', response.headers['content-type']
79
+ end
80
+
66
81
  context "with round robin selector" do
67
82
  setup do
68
83
  @client = Elasticsearch::Client.new \
@@ -135,11 +150,46 @@ class Elasticsearch::Transport::ClientIntegrationTest < Elasticsearch::Test::Int
135
150
  end
136
151
  end
137
152
 
153
+ context "with retrying on status" do
154
+ should "retry when the status does match" do
155
+ @client = Elasticsearch::Client.new \
156
+ hosts: ["localhost:#{@port}"],
157
+ logger: (ENV['QUIET'] ? nil : @logger),
158
+ retry_on_status: 400
159
+
160
+ @client.transport.logger
161
+ .expects(:debug)
162
+ .with( regexp_matches(/Attempt \d to get response/) )
163
+ .times(4)
164
+
165
+ assert_raise Elasticsearch::Transport::Transport::Errors::BadRequest do
166
+ @client.perform_request 'GET', '_foobar'
167
+ end
168
+ end
169
+ end
170
+
138
171
  context "with Faraday adapters" do
172
+ should "set the adapter with a block" do
173
+ require 'net/http/persistent'
174
+
175
+ client = Elasticsearch::Transport::Client.new url: "localhost:#{@port}" do |f|
176
+ f.adapter :net_http_persistent
177
+ end
178
+
179
+ assert_equal 'Faraday::Adapter::NetHttpPersistent',
180
+ client.transport.connections.first.connection.builder.handlers.first.name
181
+
182
+ response = @client.perform_request 'GET', '_cluster/health'
183
+ assert_equal 200, response.status
184
+ end
185
+
139
186
  should "automatically use the Patron client when loaded" do
140
187
  require 'patron'
141
188
  client = Elasticsearch::Transport::Client.new host: "localhost:#{@port}"
142
189
 
190
+ assert_equal 'Faraday::Adapter::Patron',
191
+ client.transport.connections.first.connection.builder.handlers.first.name
192
+
143
193
  response = @client.perform_request 'GET', '_cluster/health'
144
194
  assert_equal 200, response.status
145
195
  end unless JRUBY
@@ -270,5 +270,30 @@ class Elasticsearch::Transport::ClientTest < Test::Unit::TestCase
270
270
  end unless JRUBY
271
271
  end
272
272
 
273
+ context "configuring Faraday" do
274
+ setup do
275
+ Elasticsearch::Transport::Client::DEFAULT_TRANSPORT_CLASS.any_instance.unstub(:__build_connections)
276
+ begin; Object.send(:remove_const, :Typhoeus); rescue NameError; end
277
+ end
278
+
279
+ should "apply faraday adapter" do
280
+ c = Elasticsearch::Transport::Client.new do |faraday|
281
+ faraday.adapter :typhoeus
282
+ end
283
+ handlers = c.transport.connections.all.first.connection.builder.handlers
284
+
285
+ assert_includes handlers, Faraday::Adapter::Typhoeus
286
+ end
287
+
288
+ should "apply faraday response logger" do
289
+ c = Elasticsearch::Transport::Client.new do |faraday|
290
+ faraday.response :logger
291
+ end
292
+ handlers = c.transport.connections.all.first.connection.builder.handlers
293
+
294
+ assert_includes handlers, Faraday::Response::Logger
295
+ end
296
+ end
297
+
273
298
  end
274
299
  end
@@ -296,6 +296,53 @@ class Elasticsearch::Transport::Transport::BaseTest < Test::Unit::TestCase
296
296
  end
297
297
  end unless RUBY_1_8
298
298
 
299
+ context "performing a request with retry on status" do
300
+ setup do
301
+ DummyTransportPerformer.any_instance.stubs(:connections).returns(stub :get_connection => stub_everything(:failures => 1))
302
+
303
+ logger = Logger.new(STDERR)
304
+ logger.level = Logger::DEBUG
305
+ DummyTransportPerformer.any_instance.stubs(:logger).returns(logger)
306
+ @block = Proc.new { |c, u| puts "ERROR" }
307
+ end
308
+
309
+ should "not retry when the status code does not match" do
310
+ @transport = DummyTransportPerformer.new :options => { :retry_on_status => 500 }
311
+ assert_equal [500], @transport.instance_variable_get(:@retry_on_status)
312
+
313
+ @block.expects(:call).
314
+ returns(Elasticsearch::Transport::Transport::Response.new 400, 'Bad Request').
315
+ times(1)
316
+
317
+ @transport.logger.
318
+ expects(:warn).
319
+ with( regexp_matches(/Attempt \d to get response/) ).
320
+ never
321
+
322
+ assert_raise Elasticsearch::Transport::Transport::Errors::BadRequest do
323
+ @transport.perform_request('GET', '/', &@block)
324
+ end
325
+ end
326
+
327
+ should "retry when the status code does match" do
328
+ @transport = DummyTransportPerformer.new :options => { :retry_on_status => 500 }
329
+ assert_equal [500], @transport.instance_variable_get(:@retry_on_status)
330
+
331
+ @block.expects(:call).
332
+ returns(Elasticsearch::Transport::Transport::Response.new 500, 'Internal Error').
333
+ times(4)
334
+
335
+ @transport.logger.
336
+ expects(:warn).
337
+ with( regexp_matches(/Attempt \d to get response/) ).
338
+ times(4)
339
+
340
+ assert_raise Elasticsearch::Transport::Transport::Errors::InternalServerError do
341
+ @transport.perform_request('GET', '/', &@block)
342
+ end
343
+ end
344
+ end unless RUBY_1_8
345
+
299
346
  context "logging" do
300
347
  setup do
301
348
  @transport = DummyTransportPerformer.new :options => { :logger => Logger.new('/dev/null') }
@@ -426,6 +473,11 @@ class Elasticsearch::Transport::Transport::BaseTest < Test::Unit::TestCase
426
473
  @transport = DummyTransport.new
427
474
  end
428
475
 
476
+ should "close connections" do
477
+ @transport.expects(:__close_connections)
478
+ @transport.__rebuild_connections :hosts => ['foo']
479
+ end
480
+
429
481
  should "should replace the connections" do
430
482
  assert_equal [], @transport.connections
431
483
  @transport.__rebuild_connections :hosts => ['foo', 'bar']
@@ -26,6 +26,19 @@ else
26
26
  assert_instance_of ::Manticore::Client, @transport.connections.first.connection
27
27
  end
28
28
 
29
+ should "implement __close_connections" do
30
+ assert_equal 1, @transport.connections.size
31
+ @transport.__close_connections
32
+ assert_equal 0, @transport.connections.size
33
+ end
34
+
35
+ should "prevent requests after __close_connections" do
36
+ @transport.__close_connections
37
+ assert_raises ::Manticore::ClientStoppedException do
38
+ @transport.perform_request 'GET', '/'
39
+ end
40
+ end
41
+
29
42
  should "perform the request" do
30
43
  @transport.connections.first.connection.expects(:get).returns(stub_everything)
31
44
  @transport.perform_request 'GET', '/'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elasticsearch-transport
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.14
4
+ version: 1.0.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Karel Minarik
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-14 00:00:00.000000000 Z
11
+ date: 2015-12-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: multi_json
@@ -220,6 +220,20 @@ dependencies:
220
220
  - - "~>"
221
221
  - !ruby/object:Gem::Version
222
222
  version: '0.6'
223
+ - !ruby/object:Gem::Dependency
224
+ name: net-http-persistent
225
+ requirement: !ruby/object:Gem::Requirement
226
+ requirements:
227
+ - - ">="
228
+ - !ruby/object:Gem::Version
229
+ version: '0'
230
+ type: :development
231
+ prerelease: false
232
+ version_requirements: !ruby/object:Gem::Requirement
233
+ requirements:
234
+ - - ">="
235
+ - !ruby/object:Gem::Version
236
+ version: '0'
223
237
  - !ruby/object:Gem::Dependency
224
238
  name: hashie
225
239
  requirement: !ruby/object:Gem::Requirement