rsolr-cloud-lw 1.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: df8d5a6f0c5dc0b14ed1447b055ed562cf7862cd7ed9c3912bb6f662242159d0
4
+ data.tar.gz: 70260d0cb6d8565f5f55e393dc31e12fd3609e714ed59d4de52929315f17b00d
5
+ SHA512:
6
+ metadata.gz: 16c47852e31bcb22e5c90e396faa04b7b5914959bf1fcc6115ddc4ffa24746859bce28b51e54e48edc8642454381c4906ae69732900d3ee1e1817a91023e42d4
7
+ data.tar.gz: 05222647c3f9e320452b8445cde36b96f63dc220d72577b27131f459ca181660a92f617fbe7c57886d5275856c10bee7c511f1a7232d3ba390adde7225d8e6be
data/.gitignore ADDED
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ /zookeeper/
data/.rubocop.yml ADDED
@@ -0,0 +1,10 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2016-02-10 13:14:48 +0900 using RuboCop version 0.37.1.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ Metrics/LineLength:
10
+ Max: 100
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in rsolr-cloud-lw.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Kimura
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,77 @@
1
+ # Description
2
+ Customized and simplified version of [rsolr-cloud](https://github.com/enigmo/rsolr-cloud) library.
3
+
4
+ It watches SolrCloud's `/live_nodes` registry and sends every request to a random entry from that registry. It does not try to be smarter than that, i.e. be aware of collections states / cluster layouts / leaders / replicas, etc.
5
+
6
+ # RSolr::Cloud
7
+
8
+ A RSolr's connection adopter supporting SolrCloud.
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ ```ruby
15
+ gem 'rsolr-cloud-lw'
16
+ ```
17
+
18
+ And then execute:
19
+
20
+ $ bundle
21
+
22
+ Or install it yourself as:
23
+
24
+ $ gem install rsolr-cloud-lw
25
+
26
+ ## Example
27
+
28
+ ```ruby
29
+ require 'zk'
30
+ require 'rsolr/cloud'
31
+
32
+ # Create Zookeeper client for the Zookeeper ensemble in SolrCloud.
33
+ zk = ZK.new('localhost:2181,localhost:2182,localhost:2183')
34
+
35
+ # Connecting the SolrCloud through the Zookeeper.
36
+ cloud_connection = RSolr::Cloud::Connection.new(zk)
37
+
38
+ # Get rsolr client for solr_cloud.
39
+ solr_client = RSolr::Client.new(cloud_connection,
40
+ read_timeout: 60,
41
+ open_timeout: 60)
42
+
43
+ # You can use rsolr as usual but :collection option must be specified with the name of the collection.
44
+ response = solr.get('select', collection: 'collection1', params: {q: '*:*'})
45
+
46
+ ```
47
+
48
+ ## Contributing
49
+
50
+ 1. Fork it ( https://github.com/[my-github-username]/rsolr-cloud/fork )
51
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
52
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
53
+ 4. Push to the branch (`git push origin my-new-feature`)
54
+ 5. Create a new Pull Request
55
+
56
+ ## Development
57
+
58
+ To install gems which are necessary for development and testing:
59
+
60
+ ```
61
+ $ bundle install
62
+ ```
63
+
64
+ To run the test suite:
65
+
66
+ ```
67
+ $ rake
68
+ ```
69
+
70
+ The default rake task contains RuboCop and RSpec. Each task can be run separately:
71
+
72
+ ```
73
+ $ rake rubocop
74
+ ```
75
+ ```
76
+ $ rake spec
77
+ ```
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ begin
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ require 'rubocop/rake_task'
7
+ RuboCop::RakeTask.new
8
+ task default: [:rubocop, :spec]
9
+ rescue LoadError # rubocop:disable HandleExceptions
10
+ end
@@ -0,0 +1,62 @@
1
+ module RSolr
2
+ module Cloud
3
+ # RSolr connection adapter for SolrCloud
4
+ class Connection < RSolr::Connection
5
+ include MonitorMixin
6
+
7
+ ZNODE_LIVE_NODES = '/live_nodes'.freeze
8
+ ZNODE_CLUSTER_PROPS = '/clusterprops.json'.freeze
9
+
10
+ def initialize(zk)
11
+ super()
12
+ @zk = zk
13
+ init_url_scheme
14
+ init_live_node_watcher
15
+ end
16
+
17
+ def execute(client, request_context)
18
+ collection_name = request_context[:collection]
19
+ raise 'The :collection option must be specified.' unless collection_name
20
+ path = request_context[:path].to_s
21
+ query = request_context[:query]
22
+ query = query ? "?#{query}" : ''
23
+ url = select_node(collection_name)
24
+ raise RSolr::Cloud::Error::NotEnoughNodes unless url
25
+ request_context[:uri] = RSolr::Uri.create(url).merge(path + query)
26
+ super(client, request_context)
27
+ end
28
+
29
+ private
30
+
31
+ def init_url_scheme
32
+ @url_scheme = 'http'
33
+ if @zk.exists?(ZNODE_CLUSTER_PROPS)
34
+ json, _stat = @zk.get(ZNODE_CLUSTER_PROPS)
35
+ props = JSON.parse(json)
36
+ @url_scheme = props['urlScheme'] || 'http'
37
+ end
38
+ end
39
+
40
+ def select_node(collection)
41
+ synchronize { @live_nodes.sample + '/' + collection }
42
+ end
43
+
44
+ def init_live_node_watcher
45
+ @zk.register(ZNODE_LIVE_NODES) do
46
+ update_live_nodes
47
+ end
48
+ update_live_nodes
49
+ end
50
+
51
+ def update_live_nodes
52
+ synchronize do
53
+ @live_nodes = []
54
+ @zk.children(ZNODE_LIVE_NODES, watch: true).each do |node|
55
+ # "/" between host_and_port part of url and context is replaced with "_" in ZK
56
+ @live_nodes << @url_scheme + '://' + node.tr('_', '/')
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,12 @@
1
+ module RSolr
2
+ module Cloud
3
+ module Error
4
+ # This error occurs when all solr nodes aren't active.
5
+ class NotEnoughNodes < RuntimeError
6
+ def to_s
7
+ 'Not enough nodes to handle the request.'
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ module Rsolr
2
+ module Cloud
3
+ VERSION = '1.1.0'.freeze
4
+ end
5
+ end
@@ -0,0 +1,3 @@
1
+ require 'rsolr/cloud/error'
2
+ require 'rsolr/cloud/connection'
3
+ require 'rsolr/cloud/version'
@@ -0,0 +1,29 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rsolr/cloud/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'rsolr-cloud-lw'
8
+ spec.version = Rsolr::Cloud::VERSION
9
+ spec.authors = ['Shintaro Kimura', 'Alexey Serba']
10
+ spec.email = ['aserba@gmail.com']
11
+ spec.summary = 'The connection adopter supporting SolrCloud for RSolr'
12
+ spec.description = 'The connection adopter supporting SolrCloud for RSolr'
13
+ spec.homepage = ''
14
+ spec.license = 'MIT'
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ['lib']
20
+
21
+ spec.add_development_dependency 'bundler', '~> 1.7'
22
+ spec.add_development_dependency 'rake', '~> 10.0'
23
+ spec.add_development_dependency 'rspec', '~> 3.3'
24
+ spec.add_development_dependency 'activesupport', '~> 4.2'
25
+ spec.add_development_dependency 'zk-server', '~> 1.1.7'
26
+ spec.add_development_dependency 'zk', '~> 1.9.5'
27
+ spec.add_development_dependency 'rsolr', '~> 1.0.12'
28
+ spec.add_development_dependency 'rubocop', '~> 0.37.1'
29
+ end
@@ -0,0 +1,85 @@
1
+ require 'spec_helper.rb'
2
+
3
+ RSpec.describe RSolr::Cloud::Connection do
4
+ before do
5
+ @zk_in_solr = ZK.new
6
+ delete_with_children(@zk_in_solr, '/live_nodes')
7
+ wait_until(10) do
8
+ !@zk_in_solr.exists?('/live_nodes')
9
+ end
10
+ @zk_in_solr.create('/live_nodes')
11
+
12
+ ['192.168.1.21:8983_solr',
13
+ '192.168.1.22:8983_solr',
14
+ '192.168.1.23:8983_solr',
15
+ '192.168.1.24:8983_solr'
16
+ ].each do |node|
17
+ @zk_in_solr.create("/live_nodes/#{node}", '', mode: :ephemeral)
18
+ end
19
+ @zk = ZK.new
20
+ @subject = RSolr::Cloud::Connection.new @zk
21
+ end
22
+
23
+ let(:client) { double.as_null_object }
24
+
25
+ let(:http) { double(Net::HTTP).as_null_object }
26
+
27
+ it 'should configure Net::HTTP with one of live node in select or update request.' do
28
+ expect(@subject.instance_variable_get(:@live_nodes).sort).to eq(
29
+ ['http://192.168.1.21:8983/solr',
30
+ 'http://192.168.1.22:8983/solr',
31
+ 'http://192.168.1.23:8983/solr',
32
+ 'http://192.168.1.24:8983/solr'].sort)
33
+ expect(Net::HTTP).to receive(:new) do |host, port|
34
+ expect(host).to be_one_of(['192.168.1.21', '192.168.1.22', '192.168.1.23', '192.168.1.24'])
35
+ expect(port).to eq(8983)
36
+ http
37
+ end
38
+
39
+ expect(http).to receive(:request) do |request|
40
+ expect(request.path).to eq('/solr/collection1/select?q=*:*')
41
+ double.as_null_object
42
+ end
43
+ @subject.execute client, collection: 'collection1', method: :get, path: 'select', query: 'q=*:*'
44
+
45
+ expect(http).to receive(:request) do |request|
46
+ expect(request.path).to eq('/solr/collection1/update')
47
+ expect(request.body).to eq('the data')
48
+ double.as_null_object
49
+ end
50
+ @subject.execute client, collection: 'collection1',
51
+ method: :post,
52
+ path: 'update',
53
+ data: 'the data'
54
+ end
55
+
56
+ it 'should remove downed node and add recovered node.' do
57
+ @zk_in_solr.delete('/live_nodes/192.168.1.21:8983_solr')
58
+ expect { @subject.instance_variable_get(:@live_nodes).sort }.to become_soon(
59
+ ['http://192.168.1.22:8983/solr',
60
+ 'http://192.168.1.23:8983/solr',
61
+ 'http://192.168.1.24:8983/solr'].sort)
62
+ @zk_in_solr.create('/live_nodes/192.168.1.21:8983_solr', mode: :ephemeral)
63
+ expect { @subject.instance_variable_get(:@live_nodes).sort }.to become_soon(
64
+ ['http://192.168.1.21:8983/solr',
65
+ 'http://192.168.1.22:8983/solr',
66
+ 'http://192.168.1.23:8983/solr',
67
+ 'http://192.168.1.24:8983/solr'].sort)
68
+ end
69
+
70
+ it 'should obey url scheme.' do
71
+ @zk_in_solr.create('/clusterprops.json', '{"urlScheme": "https"}')
72
+ @subject = RSolr::Cloud::Connection.new @zk
73
+ expect(@subject.instance_variable_get(:@url_scheme)).to eq('https')
74
+ expect(@subject.instance_variable_get(:@live_nodes).sort).to eq(
75
+ ['https://192.168.1.21:8983/solr',
76
+ 'https://192.168.1.22:8983/solr',
77
+ 'https://192.168.1.23:8983/solr',
78
+ 'https://192.168.1.24:8983/solr'].sort)
79
+ end
80
+
81
+ after do
82
+ @zk_in_solr.close if @zk_in_solr
83
+ @zk.close if @zk
84
+ end
85
+ end
@@ -0,0 +1,65 @@
1
+ require 'rsolr'
2
+ require 'rsolr/cloud'
3
+ require 'active_support'
4
+ require 'active_support/core_ext'
5
+ require 'zk'
6
+ require 'zk-server'
7
+ require 'rspec/expectations'
8
+
9
+ module Helpers
10
+ def delete_with_children(zk, path)
11
+ zk.children(path).each do |node|
12
+ delete_with_children(zk, File.join(path, node))
13
+ end
14
+ zk.delete(path)
15
+ rescue ZK::Exceptions::NoNode # rubocop:disable HandleExceptions
16
+ # don't care if it already exists or not.
17
+ end
18
+
19
+ def wait_until(timeout = 10)
20
+ started_on = Time.now
21
+ result = false
22
+ loop do
23
+ result = yield
24
+ break if result || started_on < timeout.second.ago
25
+ Thread.pass
26
+ end
27
+ raise 'Timed out' unless result
28
+ end
29
+ end
30
+
31
+ RSpec.configure do |config|
32
+ config.include Helpers
33
+ config.before(:suite) do
34
+ ZK::Server.run do |c|
35
+ c.force_sync = false
36
+ end
37
+ end
38
+ config.after(:suite) do
39
+ ZK::Server.server.clobber!
40
+ end
41
+ end
42
+
43
+ RSpec::Matchers.define :be_one_of do |expected|
44
+ match do |actual|
45
+ expected.include?(actual)
46
+ end
47
+ end
48
+
49
+ RSpec::Matchers.define :become_soon do |expected|
50
+ match do |actual|
51
+ begin
52
+ wait_until do
53
+ actual.call == expected
54
+ end
55
+ rescue
56
+ false
57
+ else
58
+ true
59
+ end
60
+ end
61
+
62
+ def supports_block_expectations?
63
+ true
64
+ end
65
+ end
metadata ADDED
@@ -0,0 +1,172 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rsolr-cloud-lw
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Shintaro Kimura
8
+ - Alexey Serba
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2019-01-24 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ name: bundler
21
+ prerelease: false
22
+ type: :development
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.7'
28
+ - !ruby/object:Gem::Dependency
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ name: rake
35
+ prerelease: false
36
+ type: :development
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '10.0'
42
+ - !ruby/object:Gem::Dependency
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.3'
48
+ name: rspec
49
+ prerelease: false
50
+ type: :development
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '3.3'
56
+ - !ruby/object:Gem::Dependency
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '4.2'
62
+ name: activesupport
63
+ prerelease: false
64
+ type: :development
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '4.2'
70
+ - !ruby/object:Gem::Dependency
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: 1.1.7
76
+ name: zk-server
77
+ prerelease: false
78
+ type: :development
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: 1.1.7
84
+ - !ruby/object:Gem::Dependency
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: 1.9.5
90
+ name: zk
91
+ prerelease: false
92
+ type: :development
93
+ version_requirements: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: 1.9.5
98
+ - !ruby/object:Gem::Dependency
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 1.0.12
104
+ name: rsolr
105
+ prerelease: false
106
+ type: :development
107
+ version_requirements: !ruby/object:Gem::Requirement
108
+ requirements:
109
+ - - "~>"
110
+ - !ruby/object:Gem::Version
111
+ version: 1.0.12
112
+ - !ruby/object:Gem::Dependency
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: 0.37.1
118
+ name: rubocop
119
+ prerelease: false
120
+ type: :development
121
+ version_requirements: !ruby/object:Gem::Requirement
122
+ requirements:
123
+ - - "~>"
124
+ - !ruby/object:Gem::Version
125
+ version: 0.37.1
126
+ description: The connection adopter supporting SolrCloud for RSolr
127
+ email:
128
+ - aserba@gmail.com
129
+ executables: []
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - ".gitignore"
134
+ - ".rubocop.yml"
135
+ - Gemfile
136
+ - LICENSE.txt
137
+ - README.md
138
+ - Rakefile
139
+ - lib/rsolr/cloud.rb
140
+ - lib/rsolr/cloud/connection.rb
141
+ - lib/rsolr/cloud/error.rb
142
+ - lib/rsolr/cloud/version.rb
143
+ - rsolr-cloud-lw.gemspec
144
+ - spec/rsolr/cloud/connection_spec.rb
145
+ - spec/spec_helper.rb
146
+ homepage: ''
147
+ licenses:
148
+ - MIT
149
+ metadata: {}
150
+ post_install_message:
151
+ rdoc_options: []
152
+ require_paths:
153
+ - lib
154
+ required_ruby_version: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
159
+ required_rubygems_version: !ruby/object:Gem::Requirement
160
+ requirements:
161
+ - - ">="
162
+ - !ruby/object:Gem::Version
163
+ version: '0'
164
+ requirements: []
165
+ rubyforge_project:
166
+ rubygems_version: 2.6.13
167
+ signing_key:
168
+ specification_version: 4
169
+ summary: The connection adopter supporting SolrCloud for RSolr
170
+ test_files:
171
+ - spec/rsolr/cloud/connection_spec.rb
172
+ - spec/spec_helper.rb