solrb 0.2.5 → 0.2.6

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
  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