elasticsearch-transport 1.0.14 → 1.0.15

Sign up to get free protection for your applications and to get access to all the features.
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