solrb 0.2.5 → 0.2.6

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
  SHA256:
3
- metadata.gz: b33978e8d1e9f3b72dd019aba0061c0aa3954ce0751dba3e9160fd3bfa06baf3
4
- data.tar.gz: e32736f80614a2fdf417c2d5028f5ada09d1e864c7d742e9a918f172a1bad2ac
3
+ metadata.gz: d005e7cd6f9fdcbccfb46fea9352cef44d44d76adafa4e80938413e2037849ba
4
+ data.tar.gz: 87a0de829e090c6799fa9c8184f9e5439e2c31b5175bb18e557191e4e9ae26ce
5
5
  SHA512:
6
- metadata.gz: 39d7dbda2d2943d0ae2ef9298c5f91178a269e012a26d6895274e241f1313ad843d9cecb39913f823dd13bd57dc6cd887aa8cdd102ba304f479bf82932a30fbc
7
- data.tar.gz: 4d2df569275c95015768131dae59e32a159cffe9b13861892235e7089c994db9fd0216e7ce05492717da01eb7024188ddabd6d8c28f2f3bcb5e7fc3d32c53c2d
6
+ metadata.gz: b4da47651fb170b0a097c2f14cf6bfe6e1a0d2174ba88a2b95390e9aae2943b5ea957ff3603882b550f45eb6545b88eaf4286f3b848b5bdced4beed8bbc2fcd5
7
+ data.tar.gz: 2d4245600e6e8ba8cd1fff297108b080d7ed3827452afc6b13a3cc428d3ac71e63526017fe076fcbbe4823195046cba1355d8197ddf500ef246a4e883a9011ab
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- solrb (0.2.2)
4
+ solrb (0.2.5)
5
5
  addressable
6
6
  faraday
7
7
 
@@ -80,4 +80,4 @@ DEPENDENCIES
80
80
  solrb!
81
81
 
82
82
  BUNDLED WITH
83
- 1.16.6
83
+ 1.17.3
data/README.md CHANGED
@@ -15,6 +15,8 @@ Object-Oriented approach to Solr in Ruby.
15
15
  * [Single core configuration](#single-core-configuration)
16
16
  * [Multiple core configuration](#multiple-core-configuration)
17
17
  * [Solr Cloud](#solr-cloud)
18
+ * [Master-slave](#master-slave)
19
+ * [Gray list](#gray-list)
18
20
  * [Basic Authentication](#basic-authentication)
19
21
  * [Indexing](#indexing)
20
22
  * [Querying](#querying)
@@ -164,6 +166,51 @@ on_worker_boot do
164
166
  end
165
167
  ```
166
168
 
169
+ ## Master-slave
170
+
171
+ To enable master-slave mode you must define a master url and slave url on solr config block.
172
+ In solr master-slave mode you don't need to provide a solr url (`config.url` or `ENV['SOLR_URL']`).
173
+
174
+ ```ruby
175
+ Solr.configure do |config|
176
+ config.master_url = 'localhost:8983'
177
+ config.slave_url = 'localhost:8984'
178
+ # Disable select queries from master:
179
+ config.disable_read_from_master = true
180
+ # Specify Gray-list service
181
+ config.nodes_gray_list = Solr::MasterSlave::NodesGrayList::InMemory.new
182
+ end
183
+ ```
184
+
185
+ If you are using puma web server in clustered mode you must call `enable_master_slave!` on `on_worker_boot`
186
+ callback to make each puma worker connect with zookeeper.
187
+
188
+
189
+ ```ruby
190
+ on_worker_boot do
191
+ Solr.enable_master_slave!
192
+ end
193
+ ```
194
+
195
+ ### Gray list
196
+
197
+ Solrb provides two built-in services:
198
+ - `Solr::MasterSlave::NodesGrayList::Disabled` — Disabled service (default). Just does nothing.
199
+ - `Solr::MasterSlave::NodesGrayList::InMemory` — In memory service. It stores failed URLs in an instance variable, so it's not shared across threads/servers. URLs will be marked as "gray" for 5 minutes, but if all URLs are gray, the policy will try to send requests to these URLs earlier.
200
+
201
+ You are able to implement your own services with corresponding API.
202
+
203
+ ## Force node URL
204
+
205
+ You can force solrb to use a specific node URL with the `with_node_url` method:
206
+
207
+ ```ruby
208
+ Solr.with_node_url('http://localhost:9000') do
209
+ Solr::Query::Request.new(search_term: 'example', query_fields: query_fields).run
210
+ end
211
+ ```
212
+
213
+
167
214
  ## Basic Authentication
168
215
 
169
216
  Basic authentication is supported by solrb. You can enable it by providing `auth_user` and `auth_password`
@@ -16,14 +16,19 @@ require 'solr/indexing/document'
16
16
  require 'solr/indexing/request'
17
17
 
18
18
  require 'solr/cloud/helper_methods'
19
+ require 'solr/master_slave/helper_methods'
20
+ require 'solr/helper_methods'
19
21
  require 'solr/commands'
20
22
 
21
23
  module Solr
22
24
  class << self
23
25
  include Solr::Commands
24
26
  include Solr::Cloud::HelperMethods
27
+ include Solr::MasterSlave::HelperMethods
28
+ include Solr::HelperMethods
25
29
 
26
30
  CURRENT_CORE_CONFIG_VARIABLE_NAME = :solrb_current_core_config
31
+ SOLR_NODE_URL_OVERRIDE_CONFIG = :solrb_node_url_override_config
27
32
 
28
33
  attr_accessor :configuration
29
34
 
@@ -32,7 +37,11 @@ module Solr
32
37
  def configure
33
38
  yield configuration
34
39
  configuration.validate!
35
- enable_solr_cloud! unless configuration.zookeeper_url.nil?
40
+ if configuration.zookeeper_url
41
+ enable_solr_cloud!
42
+ elsif configuration.master_url
43
+ enable_master_slave!
44
+ end
36
45
  configuration
37
46
  end
38
47
 
@@ -49,6 +58,17 @@ module Solr
49
58
  Thread.current[CURRENT_CORE_CONFIG_VARIABLE_NAME] = old_core_config
50
59
  end
51
60
 
61
+ def with_node_url(url)
62
+ Thread.current[SOLR_NODE_URL_OVERRIDE_CONFIG] = url
63
+ yield
64
+ ensure
65
+ Thread.current[SOLR_NODE_URL_OVERRIDE_CONFIG] = nil
66
+ end
67
+
68
+ def node_url_override
69
+ Thread.current[SOLR_NODE_URL_OVERRIDE_CONFIG]
70
+ end
71
+
52
72
  def solr_url(path = '')
53
73
  Solr::Support::UrlHelper.solr_url(path)
54
74
  end
@@ -3,7 +3,7 @@ require 'solr/cloud/configuration'
3
3
  module Solr
4
4
  module Cloud
5
5
  module HelperMethods
6
- def active_nodes_for(collection:)
6
+ def cloud_active_nodes_for(collection:)
7
7
  collections_state_manager.active_nodes_for(collection: collection)
8
8
  end
9
9
 
@@ -5,8 +5,9 @@ require 'solr/data_import/request'
5
5
 
6
6
  module Solr
7
7
  module Commands
8
- def commit(open_searcher: true, runner_options: nil)
9
- Solr::Commit::Request.new.run(open_searcher: open_searcher,
8
+ def commit(open_searcher: true, optimize: false, runner_options: nil)
9
+ Solr::Commit::Request.new.run(optimize: optimize,
10
+ open_searcher: open_searcher,
10
11
  runner_options: runner_options)
11
12
  end
12
13
 
@@ -3,8 +3,8 @@ module Solr
3
3
  class Request
4
4
  PATH = '/update'.freeze
5
5
 
6
- def run(open_searcher: true, runner_options: nil)
7
- http_request = build_http_request(open_searcher)
6
+ def run(open_searcher: true, optimize: false, runner_options: nil)
7
+ http_request = build_http_request(open_searcher, optimize)
8
8
  options = default_runner_options.merge(runner_options || {})
9
9
  Solr::Request::Runner.call(request: http_request, **options)
10
10
  end
@@ -12,12 +12,22 @@ module Solr
12
12
  private
13
13
 
14
14
  def default_runner_options
15
- { node_selection_strategy: Solr::Request::LeaderNodeSelectionStrategy }
15
+ if Solr.cloud_enabled?
16
+ { node_selection_strategy: Solr::Request::Cloud::LeaderNodeSelectionStrategy }
17
+ elsif Solr.master_slave_enabled?
18
+ { node_selection_strategy: Solr::Request::MasterSlave::MasterNodeSelectionStrategy }
19
+ else
20
+ {}
21
+ end
16
22
  end
17
23
 
18
- def build_http_request(open_searcher)
24
+ def build_http_request(open_searcher, optimize)
19
25
  Solr::Request::HttpRequest.new(path: PATH,
20
- url_params: { commit: true, openSearcher: open_searcher },
26
+ url_params: {
27
+ commit: true,
28
+ optimize: optimize,
29
+ openSearcher: open_searcher
30
+ },
21
31
  method: :post)
22
32
  end
23
33
  end
@@ -1,3 +1,4 @@
1
+ require 'logger'
1
2
  require 'solr/core_configuration/dynamic_field'
2
3
  require 'solr/core_configuration/field'
3
4
  require 'solr/core_configuration/core_config'
@@ -11,20 +12,27 @@ module Solr
11
12
  extend Forwardable
12
13
 
13
14
  delegate [:zookeeper_url, :zookeeper_url=, :zookeeper_auth_user=, :zookeeper_auth_password=] => :@cloud_configuration
15
+ delegate [:master_url, :master_url=, :slave_url, :slave_url=, :disable_read_from_master,
16
+ :disable_read_from_master=, :nodes_gray_list, :nodes_gray_list=] => :@master_slave_configuration
14
17
 
15
18
  SOLRB_USER_AGENT_HEADER = { user_agent: "Solrb v#{Solr::VERSION}" }.freeze
16
19
 
17
20
  attr_accessor :cores, :test_connection, :auth_user, :auth_password
18
21
 
19
- attr_reader :url, :faraday_options, :cloud_configuration
22
+ attr_reader :url, :faraday_options, :faraday_configuration, :cloud_configuration,
23
+ :master_slave_configuration
24
+
25
+ attr_writer :url, :logger
20
26
 
21
27
  def initialize
22
28
  @faraday_options = {
23
29
  request: { timeout: 2, open_timeout: 8 },
24
30
  headers: SOLRB_USER_AGENT_HEADER
25
31
  }
32
+ @faraday_configuration = nil
26
33
  @cores = {}
27
34
  @cloud_configuration = Solr::Cloud::Configuration.new
35
+ @master_slave_configuration = Solr::MasterSlave::Configuration.new
28
36
  end
29
37
 
30
38
  def faraday_options=(options)
@@ -33,8 +41,8 @@ module Solr
33
41
  @faraday_options = options
34
42
  end
35
43
 
36
- def url=(value)
37
- @url = value
44
+ def faraday_configure(&block)
45
+ @faraday_configuration = block
38
46
  end
39
47
 
40
48
  def core_config_by_name(core)
@@ -87,9 +95,22 @@ module Solr
87
95
  end
88
96
 
89
97
  def validate!
90
- if !(url || @cloud_configuration.zookeeper_url || ENV['SOLR_URL'])
98
+ if !(url ||
99
+ @cloud_configuration.zookeeper_url ||
100
+ (@master_slave_configuration.master_url && @master_slave_configuration.slave_url) ||
101
+ ENV['SOLR_URL'])
91
102
  raise Solr::Errors::SolrUrlNotDefinedError
92
103
  end
93
104
  end
105
+
106
+ def logger
107
+ @logger || null_logger
108
+ end
109
+
110
+ private
111
+
112
+ def null_logger
113
+ @null_logger ||= ::Logger.new(IO::NULL)
114
+ end
94
115
  end
95
116
  end
@@ -3,9 +3,9 @@ module Solr
3
3
  class Connection
4
4
  INSTRUMENT_KEY = 'request.solrb'.freeze
5
5
 
6
- def initialize(url, faraday_options: Solr.configuration.faraday_options)
6
+ def initialize(url, faraday_options: Solr.configuration.faraday_options, faraday_configuration: Solr.configuration.faraday_configuration)
7
7
  # Allow mock the connection for testing
8
- @raw_connection = Solr.configuration.test_connection || build_faraday_connection(url, faraday_options)
8
+ @raw_connection = Solr.configuration.test_connection || build_faraday_connection(url, faraday_options, faraday_configuration)
9
9
  freeze
10
10
  end
11
11
 
@@ -29,8 +29,8 @@ module Solr
29
29
 
30
30
  private
31
31
 
32
- def build_faraday_connection(url, faraday_options)
33
- connection = Faraday.new(url, faraday_options)
32
+ def build_faraday_connection(url, faraday_options, faraday_configuration)
33
+ connection = Faraday.new(url, faraday_options, &faraday_configuration)
34
34
  if Solr.configuration.auth_user && Solr.configuration.auth_password
35
35
  connection.basic_auth(Solr.configuration.auth_user, Solr.configuration.auth_password)
36
36
  end
@@ -21,7 +21,13 @@ module Solr
21
21
  private
22
22
 
23
23
  def default_runner_options
24
- { node_selection_strategy: Solr::Request::LeaderNodeSelectionStrategy }
24
+ if Solr.cloud_enabled?
25
+ { node_selection_strategy: Solr::Request::Cloud::LeaderNodeSelectionStrategy }
26
+ elsif Solr.master_slave_enabled?
27
+ { node_selection_strategy: Solr::Request::MasterSlave::MasterNodeSelectionStrategy }
28
+ else
29
+ {}
30
+ end
25
31
  end
26
32
  end
27
33
  end
@@ -21,7 +21,13 @@ module Solr
21
21
  private
22
22
 
23
23
  def default_runner_options
24
- { node_selection_strategy: Solr::Request::LeaderNodeSelectionStrategy }
24
+ if Solr.cloud_enabled?
25
+ { node_selection_strategy: Solr::Request::Cloud::LeaderNodeSelectionStrategy }
26
+ elsif Solr.master_slave_enabled?
27
+ { node_selection_strategy: Solr::Request::MasterSlave::MasterNodeSelectionStrategy }
28
+ else
29
+ {}
30
+ end
25
31
  end
26
32
 
27
33
  def build_http_request(commit)
@@ -0,0 +1,11 @@
1
+ module Solr
2
+ module HelperMethods
3
+ def active_nodes_for(collection:)
4
+ if cloud_enabled?
5
+ cloud_active_nodes_for(collection: collection)
6
+ elsif master_slave_enabled?
7
+ master_slave_active_nodes_for(collection: collection)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -18,7 +18,13 @@ module Solr
18
18
  private
19
19
 
20
20
  def default_runner_options
21
- { node_selection_strategy: Solr::Request::LeaderNodeSelectionStrategy }
21
+ if Solr.cloud_enabled?
22
+ { node_selection_strategy: Solr::Request::Cloud::LeaderNodeSelectionStrategy }
23
+ elsif Solr.master_slave_enabled?
24
+ { node_selection_strategy: Solr::Request::MasterSlave::MasterNodeSelectionStrategy }
25
+ else
26
+ {}
27
+ end
22
28
  end
23
29
 
24
30
  def build_http_request(commit)
@@ -0,0 +1,38 @@
1
+ require 'solr/master_slave/nodes_gray_list/disabled'
2
+ require 'solr/master_slave/nodes_gray_list/in_memory'
3
+
4
+ module Solr
5
+ module MasterSlave
6
+ class Configuration
7
+ attr_accessor :master_url, :slave_url, :disable_read_from_master
8
+
9
+ attr_reader :master_slave_enabled
10
+ attr_writer :nodes_gray_list
11
+
12
+ def enable_master_slave!(_)
13
+ @master_slave_enabled = true
14
+ end
15
+
16
+ def master_slave_enabled?
17
+ @master_slave_enabled
18
+ end
19
+
20
+ def active_nodes_for(collection:)
21
+ urls = []
22
+ urls.push(master_url) unless disable_read_from_master
23
+ urls.push(*slave_url) if slave_url
24
+ nodes_gray_list.select_active(urls, collection_name: collection)
25
+ end
26
+
27
+ def nodes_gray_list
28
+ @nodes_gray_list || gray_list_disabled_instance
29
+ end
30
+
31
+ private
32
+
33
+ def gray_list_disabled_instance
34
+ @gray_list_disabled_instance ||= Solr::MasterSlave::NodesGrayList::Disabled.new
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,25 @@
1
+ require 'solr/master_slave/configuration'
2
+
3
+ module Solr
4
+ module MasterSlave
5
+ module HelperMethods
6
+ def master_slave_active_nodes_for(collection:)
7
+ master_slave_configuration.active_nodes_for(collection: collection)
8
+ end
9
+
10
+ def master_slave_enabled?
11
+ master_slave_configuration.master_slave_enabled?
12
+ end
13
+
14
+ def enable_master_slave!
15
+ master_slave_configuration.enable_master_slave!(configuration.cores.keys)
16
+ end
17
+
18
+ private
19
+
20
+ def master_slave_configuration
21
+ configuration.master_slave_configuration
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,21 @@
1
+ module Solr
2
+ module MasterSlave
3
+ module NodesGrayList
4
+ class Disabled
5
+ def add(_)
6
+ end
7
+
8
+ def remove(_)
9
+ end
10
+
11
+ def added?(_)
12
+ true
13
+ end
14
+
15
+ def select_active(urls, collection_name:)
16
+ urls
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,47 @@
1
+ module Solr
2
+ module MasterSlave
3
+ module NodesGrayList
4
+ class InMemory
5
+ attr_reader :gray_list, :removal_period
6
+
7
+ DEFAULT_REMOVAL_PERIOD = 5 * 60 # 5 minutes in seconds
8
+
9
+ def initialize(removal_period: DEFAULT_REMOVAL_PERIOD)
10
+ @gray_list = {}
11
+ @removal_period = removal_period
12
+ end
13
+
14
+ def add(url)
15
+ return if gray_list.has_key?(url)
16
+ ::Solr.configuration.logger.info("#{url} added to a gray list")
17
+ gray_list[url] = Time.now.utc
18
+ end
19
+
20
+ def remove(url)
21
+ gray_list.delete(url)
22
+ end
23
+
24
+ def added?(url)
25
+ added_at = gray_list[url]
26
+ return false unless added_at
27
+
28
+ if added_at + removal_period > Time.now.utc
29
+ true
30
+ else
31
+ remove(url)
32
+ false
33
+ end
34
+ end
35
+
36
+ def select_active(urls, collection_name:)
37
+ urls = Array(urls)
38
+ active_urls = urls.reject do |url|
39
+ collection_url = File.join(url, collection_name.to_s)
40
+ added?(collection_url)
41
+ end
42
+ active_urls.any? ? active_urls : urls
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -5,21 +5,22 @@ require 'solr/query/http_request_builder'
5
5
  module Solr
6
6
  module Query
7
7
  class Handler
8
- attr_reader :query, :page, :page_size
8
+ attr_reader :query, :rows, :start, :runner_options
9
9
 
10
10
  def self.call(opts)
11
11
  new(opts).call
12
12
  end
13
13
 
14
- def initialize(query:, page:, page_size:)
14
+ def initialize(query:, rows:, start:, runner_options: {})
15
15
  @query = query
16
- @page = page
17
- @page_size = page_size
16
+ @rows = rows
17
+ @start = start
18
+ @runner_options = runner_options || {}
18
19
  end
19
20
 
20
21
  def call
21
- http_request = Solr::Query::HttpRequestBuilder.call(query: query, page: page, page_size: page_size)
22
- solr_response = Solr::Request::Runner.call(request: http_request)
22
+ http_request = Solr::Query::HttpRequestBuilder.call(query: query, start: start, rows: rows)
23
+ solr_response = Solr::Request::Runner.call(request: http_request, **runner_options)
23
24
  Solr::Query::Response::Parser.new(request: query, solr_response: solr_response.body).to_response
24
25
  end
25
26
  end
@@ -5,16 +5,16 @@ module Solr
5
5
  class HttpRequestBuilder
6
6
  PATH = '/select'.freeze
7
7
 
8
- attr_reader :query, :page, :page_size
8
+ attr_reader :query, :start, :rows
9
9
 
10
10
  def self.call(opts)
11
11
  new(opts).call
12
12
  end
13
13
 
14
- def initialize(query:, page:, page_size:)
14
+ def initialize(query:, start:, rows:)
15
15
  @query = query
16
- @page = page
17
- @page_size = page_size
16
+ @rows = rows
17
+ @start = start
18
18
  end
19
19
 
20
20
  def call
@@ -27,13 +27,7 @@ module Solr
27
27
 
28
28
  # 🏋️
29
29
  def build_body
30
- @request_params ||= { params: solr_params.merge(wt: :json, rows: page_size.to_i, start: start) }
31
- end
32
-
33
- def start
34
- start_page = page.to_i - 1
35
- start_page = start_page < 1 ? 0 : start_page
36
- start_page * page_size
30
+ @request_params ||= { params: solr_params.merge(wt: :json, rows: rows, start: start) }
37
31
  end
38
32
 
39
33
  def solr_params
@@ -30,8 +30,11 @@ module Solr
30
30
  @filters = filters
31
31
  end
32
32
 
33
- def run(page: 1, page_size: 10)
34
- Solr::Query::Handler.call(query: self, page: page, page_size: page_size)
33
+ def run(page: nil, start: nil, rows: nil, page_size: nil, runner_options: {})
34
+ rows ||= page_size
35
+ return run_paged(page: page, page_size: rows, runner_options: runner_options) if page && rows
36
+ return run_start(start: start, rows: rows, runner_options: runner_options) if start && rows
37
+ raise ArgumentError, 'You must specify either page/rows or start/rows arguments'
35
38
  end
36
39
 
37
40
  def grouping
@@ -45,6 +48,20 @@ module Solr
45
48
  def to_h
46
49
  Solr::Query::Request::EdismaxAdapter.new(self).to_h
47
50
  end
51
+
52
+ private
53
+
54
+ def run_paged(page: 1, page_size: 10, runner_options:)
55
+ start_page = page.to_i - 1
56
+ start_page = start_page < 1 ? 0 : start_page
57
+ start = start_page * page_size
58
+
59
+ Solr::Query::Handler.call(query: self, start: start, rows: page_size, runner_options: runner_options)
60
+ end
61
+
62
+ def run_start(rows: 10, start: 0, runner_options:)
63
+ Solr::Query::Handler.call(query: self, start: start, rows: rows, runner_options: runner_options)
64
+ end
48
65
  end
49
66
  end
50
67
  end
@@ -0,0 +1,27 @@
1
+ module Solr
2
+ module Request
3
+ module Cloud
4
+ class FirstShardLeaderNodeSelectionStrategy < NodeSelectionStrategy
5
+ def call
6
+ leader = first_shard_leader_replica_node_for(collection: collection_name)
7
+ replicas = solr_cloud_active_nodes_urls.shuffle
8
+ urls = ([leader] + replicas).flatten.uniq
9
+ map_urls_to_collections(urls)
10
+ end
11
+
12
+ private
13
+
14
+ def first_shard_leader_replica_node_for(collection:)
15
+ shards = Solr.shards_for(collection: collection)
16
+ return unless shards
17
+ first_shard_name = shards.sort.first
18
+ Solr.leader_replica_node_for(collection: collection, shard: first_shard_name)
19
+ end
20
+
21
+ def solr_cloud_active_nodes_urls
22
+ Solr.active_nodes_for(collection: collection_name)
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,21 @@
1
+ module Solr
2
+ module Request
3
+ module Cloud
4
+ class LeaderNodeSelectionStrategy < NodeSelectionStrategy
5
+ def call
6
+ urls = [leader_replica_node_for(collection: collection_name)]
7
+ map_urls_to_collections(urls)
8
+ end
9
+
10
+ private
11
+
12
+ def leader_replica_node_for(collection:)
13
+ shards = Solr.shards_for(collection: collection)
14
+ return unless shards
15
+ first_shard_name = shards.sort.first
16
+ Solr.leader_replica_node_for(collection: collection, shard: first_shard_name)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -2,7 +2,8 @@ module Solr
2
2
  module Request
3
3
  class DefaultNodeSelectionStrategy < NodeSelectionStrategy
4
4
  def call
5
- Solr.active_nodes_for(collection: collection_name).shuffle
5
+ urls = Solr.active_nodes_for(collection: collection_name)
6
+ map_urls_to_collections(urls).shuffle
6
7
  end
7
8
  end
8
9
  end
@@ -0,0 +1,12 @@
1
+ module Solr
2
+ module Request
3
+ module MasterSlave
4
+ class MasterNodeSelectionStrategy < NodeSelectionStrategy
5
+ def call
6
+ urls = [Solr.configuration.master_url]
7
+ map_urls_to_collections(urls)
8
+ end
9
+ end
10
+ end
11
+ end
12
+ end
@@ -14,6 +14,12 @@ module Solr
14
14
  def call
15
15
  raise "Not implemented"
16
16
  end
17
+
18
+ private
19
+
20
+ def map_urls_to_collections(urls)
21
+ urls&.map { |u| File.join(u, collection_name.to_s) }
22
+ end
17
23
  end
18
24
  end
19
25
  end
@@ -1,7 +1,8 @@
1
1
  require 'solr/request/node_selection_strategy'
2
2
  require 'solr/request/default_node_selection_strategy'
3
- require 'solr/request/first_shard_leader_node_selection_strategy'
4
- require 'solr/request/leader_node_selection_strategy'
3
+ require 'solr/request/cloud/first_shard_leader_node_selection_strategy'
4
+ require 'solr/request/cloud/leader_node_selection_strategy'
5
+ require 'solr/request/master_slave/master_node_selection_strategy'
5
6
  require 'solr/errors/solr_query_error'
6
7
  require 'solr/errors/solr_connection_failed_error'
7
8
  require 'solr/errors/no_active_solr_nodes_error'
@@ -39,6 +40,9 @@ module Solr
39
40
  raise Solr::Errors::SolrQueryError, solr_response.error_message unless solr_response.ok?
40
41
  return solr_response
41
42
  rescue Faraday::ConnectionFailed, Faraday::TimeoutError, Errno::EADDRNOTAVAIL => e
43
+ if Solr.master_slave_enabled?
44
+ Solr.configuration.nodes_gray_list.add(node_url)
45
+ end
42
46
  solr_url_errors[node_url] = "#{e.class.name} - #{e.message}"
43
47
  # Try next node
44
48
  end
@@ -51,7 +55,13 @@ module Solr
51
55
 
52
56
  def solr_urls
53
57
  @solr_urls ||= begin
54
- urls = Solr.cloud_enabled? ? solr_cloud_collection_urls : [Solr.current_core_config.url]
58
+ urls = if Solr.node_url_override
59
+ [File.join(Solr.node_url_override, collection_name.to_s)]
60
+ elsif Solr.cloud_enabled? || Solr.master_slave_enabled?
61
+ node_selection_strategy.call(collection_name)
62
+ else
63
+ [Solr.current_core_config.url]
64
+ end
55
65
  unless urls && urls.any?
56
66
  raise Solr::Errors::NoActiveSolrNodesError
57
67
  end
@@ -59,11 +69,6 @@ module Solr
59
69
  end
60
70
  end
61
71
 
62
- def solr_cloud_collection_urls
63
- urls = node_selection_strategy.call(collection_name)
64
- urls&.map { |u| File.join(u, collection_name.to_s) }
65
- end
66
-
67
72
  def collection_name
68
73
  Solr.current_core_config.name
69
74
  end
@@ -18,11 +18,16 @@ module Solr
18
18
  end
19
19
 
20
20
  def core_url
21
- Solr.cloud_enabled? ? solr_cloud_url : current_core.uri
21
+ if Solr.cloud_enabled? || Solr.master_slave_enabled?
22
+ solr_cloud_or_master_slave_url
23
+ else
24
+ current_core.uri
25
+ end
22
26
  end
23
27
 
24
- def solr_cloud_url
25
- File.join(Solr.active_nodes_for(collection: current_core.name.to_s).first, current_core.name.to_s)
28
+ def solr_cloud_or_master_slave_url
29
+ url = Solr.active_nodes_for(collection: current_core.name.to_s).first
30
+ File.join(url, current_core.name.to_s)
26
31
  end
27
32
 
28
33
  def current_core
@@ -1,3 +1,3 @@
1
1
  module Solr
2
- VERSION = '0.2.5'.freeze
2
+ VERSION = '0.2.6'.freeze
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: solrb
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.5
4
+ version: 0.2.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Adriano Luz
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2019-04-11 00:00:00.000000000 Z
13
+ date: 2019-11-13 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: addressable
@@ -198,8 +198,13 @@ files:
198
198
  - lib/solr/errors/solr_url_not_defined_error.rb
199
199
  - lib/solr/errors/zookeeper_required.rb
200
200
  - lib/solr/grouped_document_collection.rb
201
+ - lib/solr/helper_methods.rb
201
202
  - lib/solr/indexing/document.rb
202
203
  - lib/solr/indexing/request.rb
204
+ - lib/solr/master_slave/configuration.rb
205
+ - lib/solr/master_slave/helper_methods.rb
206
+ - lib/solr/master_slave/nodes_gray_list/disabled.rb
207
+ - lib/solr/master_slave/nodes_gray_list/in_memory.rb
203
208
  - lib/solr/query/handler.rb
204
209
  - lib/solr/query/http_request_builder.rb
205
210
  - lib/solr/query/request.rb
@@ -235,10 +240,11 @@ files:
235
240
  - lib/solr/query/response/field_facets.rb
236
241
  - lib/solr/query/response/parser.rb
237
242
  - lib/solr/query/response/spellcheck.rb
243
+ - lib/solr/request/cloud/first_shard_leader_node_selection_strategy.rb
244
+ - lib/solr/request/cloud/leader_node_selection_strategy.rb
238
245
  - lib/solr/request/default_node_selection_strategy.rb
239
- - lib/solr/request/first_shard_leader_node_selection_strategy.rb
240
246
  - lib/solr/request/http_request.rb
241
- - lib/solr/request/leader_node_selection_strategy.rb
247
+ - lib/solr/request/master_slave/master_node_selection_strategy.rb
242
248
  - lib/solr/request/node_selection_strategy.rb
243
249
  - lib/solr/request/runner.rb
244
250
  - lib/solr/response.rb
@@ -1,24 +0,0 @@
1
- module Solr
2
- module Request
3
- class FirstShardLeaderNodeSelectionStrategy < NodeSelectionStrategy
4
- def call
5
- leader = first_shard_leader_replica_node_for(collection: collection_name)
6
- replicas = solr_cloud_active_nodes_urls.shuffle
7
- ([leader] + replicas).flatten.uniq
8
- end
9
-
10
- private
11
-
12
- def first_shard_leader_replica_node_for(collection:)
13
- shards = Solr.shards_for(collection: collection)
14
- return unless shards
15
- first_shard_name = shards.sort.first
16
- Solr.leader_replica_node_for(collection: collection, shard: first_shard_name)
17
- end
18
-
19
- def solr_cloud_active_nodes_urls
20
- Solr.active_nodes_for(collection: collection_name)
21
- end
22
- end
23
- end
24
- end
@@ -1,18 +0,0 @@
1
- module Solr
2
- module Request
3
- class LeaderNodeSelectionStrategy < NodeSelectionStrategy
4
- def call
5
- [leader_replica_node_for(collection: collection_name)]
6
- end
7
-
8
- private
9
-
10
- def leader_replica_node_for(collection:)
11
- shards = Solr.shards_for(collection: collection)
12
- return unless shards
13
- first_shard_name = shards.sort.first
14
- Solr.leader_replica_node_for(collection: collection, shard: first_shard_name)
15
- end
16
- end
17
- end
18
- end