elasticsearch-transport 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.txt +13 -0
  4. data/README.md +276 -0
  5. data/Rakefile +67 -0
  6. data/elasticsearch-transport.gemspec +52 -0
  7. data/lib/elasticsearch-transport.rb +1 -0
  8. data/lib/elasticsearch/transport.rb +29 -0
  9. data/lib/elasticsearch/transport/client.rb +123 -0
  10. data/lib/elasticsearch/transport/extensions/test_cluster.rb +163 -0
  11. data/lib/elasticsearch/transport/transport/base.rb +236 -0
  12. data/lib/elasticsearch/transport/transport/connections/collection.rb +93 -0
  13. data/lib/elasticsearch/transport/transport/connections/connection.rb +117 -0
  14. data/lib/elasticsearch/transport/transport/connections/selector.rb +63 -0
  15. data/lib/elasticsearch/transport/transport/errors.rb +73 -0
  16. data/lib/elasticsearch/transport/transport/http/curb.rb +70 -0
  17. data/lib/elasticsearch/transport/transport/http/faraday.rb +59 -0
  18. data/lib/elasticsearch/transport/transport/response.rb +20 -0
  19. data/lib/elasticsearch/transport/transport/serializer/multi_json.rb +36 -0
  20. data/lib/elasticsearch/transport/transport/sniffer.rb +46 -0
  21. data/lib/elasticsearch/transport/version.rb +5 -0
  22. data/test/integration/client_test.rb +117 -0
  23. data/test/integration/transport_test.rb +37 -0
  24. data/test/profile/client_benchmark_test.rb +107 -0
  25. data/test/test_extensions.rb +139 -0
  26. data/test/test_helper.rb +58 -0
  27. data/test/unit/client_test.rb +109 -0
  28. data/test/unit/connection_collection_test.rb +83 -0
  29. data/test/unit/connection_selector_test.rb +64 -0
  30. data/test/unit/connection_test.rb +90 -0
  31. data/test/unit/serializer_test.rb +16 -0
  32. data/test/unit/sniffer_test.rb +146 -0
  33. data/test/unit/transport_base_test.rb +402 -0
  34. data/test/unit/transport_curb_test.rb +59 -0
  35. data/test/unit/transport_faraday_test.rb +73 -0
  36. metadata +342 -0
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in elasticsearch-transport.gemspec
4
+ gemspec
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2013 Elasticsearch
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
@@ -0,0 +1,276 @@
1
+ # Elasticsearch::Client
2
+
3
+ **This library is part of the [`elasticsearch-ruby`](https://github.com/elasticsearch/elasticsearch-ruby/) package;
4
+ please refer to it, unless you want to use this library standalone.**
5
+
6
+ ----
7
+
8
+ The `elasticsearch-client` library provides a Ruby client for connecting
9
+ to an [Elasticsearch](http://elasticsearch.org) cluster.
10
+
11
+ It handles connecting to multiple nodes in the cluster, rotating across connections,
12
+ logging and tracing requests and responses, maintaining failed connections,
13
+ discovering nodes in the cluster, and provides an abstraction for
14
+ data serialization and transport.
15
+
16
+ It does not handle calling the Elasticsearch API;
17
+ see the [`elasticsearch-api`](https://github.com/elasticsearch/elasticsearch-ruby/tree/master/elasticsearch-api) library.
18
+
19
+ The library is compatible with Ruby 1.8.7 or higher.
20
+
21
+ Features overview:
22
+
23
+ * Pluggable logging and tracing
24
+ * Plugabble connection selection strategies (round-robin, random, custom)
25
+ * Pluggable transport implementation, customizable and extendable
26
+ * Pluggable serializer implementation
27
+ * Request retries and dead connections handling
28
+ * Node reloading (based on cluster state) on errors or on demand
29
+
30
+ ## Installation
31
+
32
+ Install the package from [Rubygems](https://rubygems.org):
33
+
34
+ gem install elasticsearch-client
35
+
36
+ To use an unreleased version, either add it to your `Gemfile` for [Bundler](http://gembundler.com):
37
+
38
+ gem 'elasticsearch-client', git: 'git://github.com/elasticsearch/elasticsearch-ruby.git'
39
+
40
+ or install it from a source code checkout:
41
+
42
+ git clone https://github.com/elasticsearch/elasticsearch-ruby.git
43
+ cd elasticsearch-ruby/elasticsearch-client
44
+ bundle install
45
+ rake install
46
+
47
+ ## Example Usage
48
+
49
+ In the simplest form, connect to Elasticsearch running on <http://localhost:9200>
50
+ without any configuration:
51
+
52
+ require 'elasticsearch/client'
53
+
54
+ client = Elasticsearch::Client.new
55
+ response = client.perform_request 'GET', '_cluster/health'
56
+ # => #<Elasticsearch::Transport::Transport::Response:0x007fc5d506ce38 @status=200, @body={ ... } >
57
+
58
+ ## Configuration
59
+
60
+ The client supports many configurations options for setting up and managing connections,
61
+ configuring logging, customizing the transport library, etc.
62
+
63
+ ### Setting Hosts
64
+
65
+ To connect to a specific Elasticsearch host:
66
+
67
+ Elasticsearch::Client.new host: 'search.myserver.com'
68
+
69
+ To connect to a host with specific port:
70
+
71
+ Elasticsearch::Client.new host: 'myhost:8080'
72
+
73
+ To connect to multiple hosts:
74
+
75
+ Elasticsearch::Client.new hosts: ['myhost1', 'myhost2']
76
+
77
+ Instead of Strings, you can pass host information as an array of Hashes:
78
+
79
+ Elasticsearch::Client.new hosts: [ { host: 'myhost1', port: 8080 }, { host: 'myhost2', port: 8080 } ]
80
+
81
+ ### Logging
82
+
83
+ To log requests and responses to standard output with the default logger (an instance of Ruby's {::Logger}) class):
84
+
85
+ Elasticsearch::Client.new log: true
86
+
87
+ To trace requests and responses in the `curl` format:
88
+
89
+ Elasticsearch::Client.new trace: true
90
+
91
+ You can customize the default logger or tracer:
92
+
93
+ client.transport.logger.formatter = proc { |s, d, p, m| "#{s}: #{m}\n" }
94
+ client.transport.logger.level = Logger::INFO
95
+
96
+ You can use a custom {::Logger} instance:
97
+
98
+ Elasticsearch::Client.new logger: Logger.new(STDERR)
99
+
100
+ You can pass the client any conforming logger implementation:
101
+
102
+ require 'logging' # https://github.com/TwP/logging/
103
+
104
+ log = Logging.logger['elasticsearch']
105
+ log.add_appenders Logging.appenders.stdout
106
+ log.level = :info
107
+
108
+ client = Elasticsearch::Client.new logger: log
109
+
110
+ ### Randomizing Hosts
111
+
112
+ If you pass multiple hosts to the client, it rotates across them in a round-robin fashion, by default.
113
+ When the same client would be running in multiple processes (eg. in a Ruby web server such as Thin),
114
+ it might keep connecting to the same nodes "at once". To prevent this, you can randomize the hosts
115
+ collection on initialization and reloading:
116
+
117
+ Elasticsearch::Client.new hosts: ['localhost:9200', 'localhost:9201'], randomize_hosts: true
118
+
119
+ ### Retrying on Failures
120
+
121
+ When the client is initialized with multiple hosts, it makes sense to retry a failed request
122
+ on a different host:
123
+
124
+ Elasticsearch::Client.new hosts: ['localhost:9200', 'localhost:9201'], retry_on_failure: true
125
+
126
+ You can specify how many times should the client retry the request before it raises an exception:
127
+
128
+ Elasticsearch::Client.new hosts: ['localhost:9200', 'localhost:9201'], retry_on_failure: 5
129
+
130
+ ### Reloading Hosts
131
+
132
+ Elasticsearch by default dynamically discovers new nodes in the cluster. You can leverage this
133
+ in the client, and periodically check for new nodes to spread the load.
134
+
135
+ To retrieve and use the information from the
136
+ [_Nodes Info API_](http://www.elasticsearch.org/guide/reference/api/admin-cluster-nodes-info/)
137
+ on every 10,000th request:
138
+
139
+ Elasticsearch::Client.new hosts: ['localhost:9200', 'localhost:9201'], reload_connections: true
140
+
141
+ You can pass a specific number of requests after which the reloading should be performed:
142
+
143
+ Elasticsearch::Client.new hosts: ['localhost:9200', 'localhost:9201'], reload_connections: 1_000
144
+
145
+ To reload connections on failures, use:
146
+
147
+ Elasticsearch::Client.new hosts: ['localhost:9200', 'localhost:9201'], reload_on_failure: true
148
+
149
+ The reloading will timeout if not finished under 1 second by default. To change the setting:
150
+
151
+ Elasticsearch::Client.new hosts: ['localhost:9200', 'localhost:9201'], sniffer_timeout: 3
152
+
153
+ ### Connection Selector
154
+
155
+ By default, the client will rotate the connections in a round-robin fashion, using the
156
+ {Elasticsearch::Transport::Transport::Connections::Selector::RoundRobin} strategy.
157
+
158
+ You can implement your own strategy to customize the behaviour. For example,
159
+ let's have a "rack aware" strategy, which will prefer the nodes with a specific attribute,
160
+ and only when these are not be available, will use the rest:
161
+
162
+ class RackIdSelector
163
+ include Elasticsearch::Transport::Transport::Connections::Selector::Base
164
+
165
+ def select(options={})
166
+ connections.reject do |c|
167
+ # Try selecting the nodes with a `rack_id:x1` attribute first
168
+ c.host[:attributes] && c.host[:attributes][:rack_id] == 'x1'
169
+ end.sample || connections.to_a.sample
170
+ end
171
+ end
172
+
173
+ Elasticsearch::Client.new hosts: ['x1.search.org', 'x2.search.org'], selector_class: RackIdSelector
174
+
175
+ ### Transport Implementations
176
+
177
+ By default, the client will use the [_Faraday_](https://rubygems.org/gems/faraday) HTTP library
178
+ as a transport implementation. You can configure the _Faraday_ instance, eg. to use a different
179
+ HTTP adapter or custom middleware, by passing a configuration block to the client constructor:
180
+
181
+ require 'typhoeus'
182
+ require 'typhoeus/adapters/faraday'
183
+
184
+ configuration = lambda do |f|
185
+ f.response :logger
186
+ f.adapter :typhoeus
187
+ end
188
+
189
+ transport = Elasticsearch::Transport::Transport::HTTP::Faraday.new \
190
+ hosts: [ { host: 'localhost', port: '9200' } ],
191
+ &configuration
192
+
193
+ client = Elasticsearch::Client.new transport: transport
194
+
195
+ You can also use a [_Curb_](https://rubygems.org/gems/curb) based transport implementation:
196
+
197
+ require 'curb'
198
+ require 'elasticsearch/transport/transport/http/curb'
199
+
200
+ client = Elasticsearch::Client.new transport_class: Elasticsearch::Transport::Transport::HTTP::Curb
201
+
202
+ It's possible to customize the _Curb_ instance by passing a block to the constructor as well:
203
+
204
+ configuration = lambda { |c| c.verbose = true }
205
+
206
+ transport = Elasticsearch::Transport::Transport::HTTP::Curb.new \
207
+ hosts: [ { host: 'localhost', port: '9200' } ],
208
+ &configuration
209
+
210
+ client = Elasticsearch::Client.new transport: transport
211
+
212
+ You can write your own transport implementation easily, by including the
213
+ {Elasticsearch::Transport::Transport::Base} module, implementing the required contract,
214
+ and passing it to the client as the `transport_class` parameter. All the arguments
215
+ passed to client will be passed as the `:options` parameter to the transport constructor.
216
+
217
+ ### Serializer Implementations
218
+
219
+ By default, the [MultiJSON](http://rubygems.org/gems/multi_json) library is used as the
220
+ serializer implementation, and it will pick up the "right" adapter based on gems available.
221
+
222
+ The serialization component is pluggable, though, so you can write your own by including the
223
+ {Elasticsearch::Transport::Transport::Serializer::Base} module, implementing the required contract,
224
+ and passing it to the client as the `serializer_class` or `serializer` parameter.
225
+
226
+ ## Development and Community
227
+
228
+ For local development, clone the repository and run `bundle install`. See `rake -T` for a list of
229
+ available Rake tasks for running tests, generating documentation, starting a testing cluster, etc.
230
+
231
+ Bug fixes and features must be accompanying by unit tests. Integration tests are written in Ruby 1.9 syntax.
232
+
233
+ Github's pull requests and issues are used to send code contributions and bug reports.
234
+
235
+ ## The Architecture
236
+
237
+ * {Elasticsearch::Transport::Client} is composed of {Elasticsearch::Transport::Transport}
238
+
239
+ * {Elasticsearch::Transport::Transport} is composed of {Elasticsearch::Transport::Transport::Connections},
240
+ and an instance of logger, tracer, serializer and sniffer.
241
+
242
+ * Logger and tracer can be any object conforming to Ruby logging interface,
243
+ ie. an instance of [`Logger`](http://www.ruby-doc.org/stdlib-1.9.3/libdoc/logger/rdoc/Logger.html),
244
+ [_log4r_](https://rubygems.org/gems/log4r), [_logging_](https://github.com/TwP/logging/), etc.
245
+
246
+ * The {Elasticsearch::Transport::Transport::Serializer::Base} implementations handle converting data for Elasticsearch
247
+ (eg. to JSON). You can implement your own serializer.
248
+
249
+ * {Elasticsearch::Transport::Transport::Sniffer} allows to discover nodes in the cluster and use them as connections.
250
+
251
+ * {Elasticsearch::Transport::Transport::Connections::Collection} is composed of
252
+ {Elasticsearch::Transport::Transport::Connections::Connection} instances and a selector instance.
253
+
254
+ * {Elasticsearch::Transport::Transport::Connections::Connection} contains the connection attributes such as hostname and port,
255
+ as well as the concrete persistent "session" connected to a specific node.
256
+
257
+ * The {Elasticsearch::Transport::Transport::Connections::Selector::Base} implementations allow to choose connections
258
+ from the pool, eg. in a round-robin or random fashion. You can implement your own selector strategy.
259
+
260
+ ## License
261
+
262
+ This software is licensed under the Apache 2 license, quoted below.
263
+
264
+ Copyright (c) 2013 Elasticsearch <http://www.elasticsearch.org>
265
+
266
+ Licensed under the Apache License, Version 2.0 (the "License");
267
+ you may not use this file except in compliance with the License.
268
+ You may obtain a copy of the License at
269
+
270
+ http://www.apache.org/licenses/LICENSE-2.0
271
+
272
+ Unless required by applicable law or agreed to in writing, software
273
+ distributed under the License is distributed on an "AS IS" BASIS,
274
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
275
+ See the License for the specific language governing permissions and
276
+ limitations under the License.
@@ -0,0 +1,67 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ desc "Run unit tests"
4
+ task :default => 'test:unit'
5
+ task :test => 'test:unit'
6
+
7
+ # ----- Test tasks ------------------------------------------------------------
8
+
9
+ require 'rake/testtask'
10
+ namespace :test do
11
+ Rake::TestTask.new(:unit) do |test|
12
+ test.libs << 'lib' << 'test'
13
+ test.test_files = FileList["test/unit/**/*_test.rb"]
14
+ # test.verbose = true
15
+ # test.warning = true
16
+ end
17
+
18
+ Rake::TestTask.new(:integration) do |test|
19
+ test.libs << 'lib' << 'test'
20
+ test.test_files = FileList["test/integration/**/*_test.rb"]
21
+ end
22
+
23
+ Rake::TestTask.new(:all) do |test|
24
+ test.libs << 'lib' << 'test'
25
+ test.test_files = FileList["test/unit/**/*_test.rb", "test/integration/**/*_test.rb"]
26
+ end
27
+
28
+ Rake::TestTask.new(:profile) do |test|
29
+ test.libs << 'lib' << 'test'
30
+ test.test_files = FileList["test/profile/**/*_test.rb"]
31
+ end
32
+
33
+ namespace :server do
34
+ desc "Start Elasticsearch nodes for tests"
35
+ task :start do
36
+ $LOAD_PATH << File.expand_path('../lib', __FILE__) << File.expand_path('../test', __FILE__)
37
+ require 'elasticsearch/transport'
38
+ require 'elasticsearch/transport/extensions/test_cluster'
39
+ Elasticsearch::TestCluster.start
40
+ end
41
+
42
+ desc "Stop Elasticsearch nodes for tests"
43
+ task :stop do
44
+ $LOAD_PATH << File.expand_path('../lib', __FILE__) << File.expand_path('../test', __FILE__)
45
+ require 'elasticsearch/transport'
46
+ require 'elasticsearch/transport/extensions/test_cluster'
47
+ Elasticsearch::TestCluster.stop
48
+ end
49
+ end
50
+ end
51
+
52
+ # ----- Documentation tasks ---------------------------------------------------
53
+
54
+ require 'yard'
55
+ YARD::Rake::YardocTask.new(:doc) do |t|
56
+ t.options = %w| --embed-mixins --markup=markdown |
57
+ end
58
+
59
+ # ----- Code analysis tasks ---------------------------------------------------
60
+
61
+ if defined?(RUBY_VERSION) && RUBY_VERSION > '1.9'
62
+ require 'cane/rake_task'
63
+ Cane::RakeTask.new(:quality) do |cane|
64
+ cane.abc_max = 15
65
+ cane.no_style = true
66
+ end
67
+ end
@@ -0,0 +1,52 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'elasticsearch/transport/version'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "elasticsearch-transport"
8
+ s.version = Elasticsearch::Transport::VERSION
9
+ s.authors = ["Karel Minarik"]
10
+ s.email = ["karel.minarik@elasticsearch.org"]
11
+ s.summary = "Ruby client for Elasticsearch."
12
+ s.homepage = "https://github.com/elasticsearch/elasticsearch-ruby/tree/master/elasticsearch-transport"
13
+ s.license = "Apache 2"
14
+
15
+ s.files = `git ls-files`.split($/)
16
+ s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
18
+ s.require_paths = ["lib"]
19
+
20
+ s.extra_rdoc_files = [ "README.md", "LICENSE.txt" ]
21
+ s.rdoc_options = [ "--charset=UTF-8" ]
22
+
23
+ s.add_dependency "multi_json"
24
+ s.add_dependency "faraday"
25
+
26
+ if defined?(RUBY_VERSION) && RUBY_VERSION < '1.9'
27
+ s.add_dependency "system_timer"
28
+ end
29
+ s.add_development_dependency "bundler", "> 1"
30
+ s.add_development_dependency "rake"
31
+
32
+ s.add_development_dependency "ansi"
33
+ s.add_development_dependency "shoulda-context"
34
+ s.add_development_dependency "mocha"
35
+ s.add_development_dependency "turn"
36
+ s.add_development_dependency "yard"
37
+ s.add_development_dependency "ruby-prof"
38
+
39
+ # Gems for testing integrations
40
+ s.add_development_dependency "curb"
41
+ s.add_development_dependency "typhoeus"
42
+
43
+ if defined?(RUBY_VERSION) && RUBY_VERSION > '1.9'
44
+ s.add_development_dependency "simplecov"
45
+ s.add_development_dependency "cane"
46
+ s.add_development_dependency "require-prof"
47
+ end
48
+
49
+ s.description = <<-DESC.gsub(/^ /, '')
50
+ Ruby client for Elasticsearch. See the `elasticsearch` gem for full integration.
51
+ DESC
52
+ end
@@ -0,0 +1 @@
1
+ require 'elasticsearch/transport'
@@ -0,0 +1,29 @@
1
+ require "time"
2
+ require "timeout"
3
+ require "multi_json"
4
+ require "faraday"
5
+
6
+ require "elasticsearch/transport/transport/serializer/multi_json"
7
+ require "elasticsearch/transport/transport/sniffer"
8
+ require "elasticsearch/transport/transport/response"
9
+ require "elasticsearch/transport/transport/errors"
10
+ require "elasticsearch/transport/transport/base"
11
+ require "elasticsearch/transport/transport/connections/selector"
12
+ require "elasticsearch/transport/transport/connections/connection"
13
+ require "elasticsearch/transport/transport/connections/collection"
14
+ require "elasticsearch/transport/transport/http/faraday"
15
+ require "elasticsearch/transport/client"
16
+
17
+ require "elasticsearch/transport/version"
18
+
19
+ module Elasticsearch
20
+ module Client
21
+
22
+ # A convenience wrapper for {::Elasticsearch::Transport::Client#initialize}.
23
+ #
24
+ def new(arguments={})
25
+ Elasticsearch::Transport::Client.new(arguments)
26
+ end
27
+ extend self
28
+ end
29
+ end