sunspot-rails-failover 0.0.2 → 0.0.3
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.
- data/.gitignore +4 -0
- data/.rvmrc +1 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.md +51 -0
- data/Rakefile +7 -0
- data/lib/sunspot-rails-failover.rb +39 -0
- data/lib/sunspot-rails-failover/exception_handler_adapter.rb +22 -0
- data/lib/sunspot-rails-failover/master_slave_with_failover_session_proxy.rb +31 -0
- data/lib/sunspot-rails-failover/version.rb +7 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/sunspot-rails-failover/exception_handler_adapter_spec.rb +34 -0
- data/spec/sunspot-rails-failover/master_slave_with_failover_session_proxy_spec.rb +59 -0
- data/spec/sunspot-rails-failover_spec.rb +36 -0
- data/spec/support/my_exception_handler.rb +4 -0
- data/sunspot-rails-failover.gemspec +25 -0
- metadata +25 -6
data/.gitignore
ADDED
data/.rvmrc
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
rvm use 1.9.2@sunspot-rails-failover --create
|
data/Gemfile
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2011 Justin Ko
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# sunspot-rails-failover
|
|
2
|
+
|
|
3
|
+
Sunspot comes with `MasterSlaveSessionProxy` that does the following:
|
|
4
|
+
|
|
5
|
+
> This session proxy implementation allows Sunspot to be used with a
|
|
6
|
+
> master/slave Solr deployment. All write methods are delegated to a master
|
|
7
|
+
> session, and read methods are delegated to a slave session.
|
|
8
|
+
|
|
9
|
+
What this simple gem does is provide failover support if the slave session
|
|
10
|
+
goes down. Reads *and* writes are called on the master session.
|
|
11
|
+
|
|
12
|
+
## Setup
|
|
13
|
+
|
|
14
|
+
Your config/sunspot.yml file should look something like this:
|
|
15
|
+
|
|
16
|
+
development:
|
|
17
|
+
master_solr:
|
|
18
|
+
url: http://localhost:8984/solr
|
|
19
|
+
solr:
|
|
20
|
+
url: http://localhost:8985/solr
|
|
21
|
+
|
|
22
|
+
NOTE: You do *not* have to have a master session. If a master session is
|
|
23
|
+
not detected, sunspot-rails-failover will default to what sunspot_rails
|
|
24
|
+
provides.
|
|
25
|
+
|
|
26
|
+
Next, add an initializer (maybe initializers/sunspot.rb) with the following
|
|
27
|
+
code:
|
|
28
|
+
|
|
29
|
+
Sunspot::Rails::Failover.setup
|
|
30
|
+
|
|
31
|
+
## Exception handling
|
|
32
|
+
|
|
33
|
+
sunspot-rails-failover supports exception handling for committing and
|
|
34
|
+
searching. Currently, it will use Hoptoad by default if it is installed.
|
|
35
|
+
The exception is passed to `HoptoadNotifier.notify`.
|
|
36
|
+
|
|
37
|
+
You can also use a custom class/module to customize how you want to handle the
|
|
38
|
+
exception. In `initializers/sunspot.rb`:
|
|
39
|
+
|
|
40
|
+
module MyExceptionHandler
|
|
41
|
+
def self.handle(exception)
|
|
42
|
+
Notifier.deliver_exception_message(exception)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
Sunspot::Rails::Failover.exception_handler = MyExceptionHandler
|
|
47
|
+
Sunspot::Rails::Failover.setup
|
|
48
|
+
|
|
49
|
+
## Copyright
|
|
50
|
+
|
|
51
|
+
Copyright (c) 2011 Justin Ko. See LICENSE for details.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'sunspot'
|
|
2
|
+
require 'sunspot-rails-failover/master_slave_with_failover_session_proxy'
|
|
3
|
+
require 'sunspot-rails-failover/exception_handler_adapter'
|
|
4
|
+
|
|
5
|
+
module Sunspot
|
|
6
|
+
module Rails
|
|
7
|
+
module Failover
|
|
8
|
+
class << self
|
|
9
|
+
attr_accessor :exception_handler
|
|
10
|
+
|
|
11
|
+
def setup
|
|
12
|
+
Sunspot.session = if Sunspot::Rails.configuration.has_master?
|
|
13
|
+
Sunspot::SessionProxy::MasterSlaveWithFailoverSessionProxy.new(
|
|
14
|
+
Sunspot::Session.new(master_config), Sunspot::Session.new(slave_config)
|
|
15
|
+
)
|
|
16
|
+
else
|
|
17
|
+
Sunspot::SessionProxy::ThreadLocalSessionProxy.new(slave_config)
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def slave_config
|
|
24
|
+
build_config('solr', 'url')
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def master_config
|
|
28
|
+
build_config('master_solr', 'url')
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def build_config(*keys)
|
|
32
|
+
Sunspot::Configuration.build.tap do |config|
|
|
33
|
+
config.solr.url = Sunspot::Rails.configuration.send :user_configuration_from_key, *keys
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Sunspot
|
|
2
|
+
module Rails
|
|
3
|
+
module Failover
|
|
4
|
+
module ExceptionHandlerAdapter
|
|
5
|
+
|
|
6
|
+
def self.handle(exception)
|
|
7
|
+
case exception_handler
|
|
8
|
+
when :hoptoad, nil
|
|
9
|
+
HoptoadNotifier.notify(exception) if defined?(HoptoadNotifier)
|
|
10
|
+
when Class
|
|
11
|
+
exception_handler.handle(exception)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def self.exception_handler
|
|
16
|
+
Failover.exception_handler
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
module Sunspot
|
|
2
|
+
module SessionProxy
|
|
3
|
+
class MasterSlaveWithFailoverSessionProxy < MasterSlaveSessionProxy
|
|
4
|
+
|
|
5
|
+
attr_accessor :exception
|
|
6
|
+
|
|
7
|
+
def commit
|
|
8
|
+
with_exception_handling do
|
|
9
|
+
master_session.commit
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def search(*types, &block)
|
|
14
|
+
[slave_session, master_session].any? do |session|
|
|
15
|
+
with_exception_handling { session.search(*types, &block) }
|
|
16
|
+
end or raise(exception)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def with_exception_handling
|
|
22
|
+
yield
|
|
23
|
+
rescue Exception => exception
|
|
24
|
+
Sunspot::Rails::Failover::ExceptionHandlerAdapter.handle(exception)
|
|
25
|
+
self.exception = exception
|
|
26
|
+
false
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
require 'hoptoad_notifier'
|
|
4
|
+
|
|
5
|
+
shared_examples_for 'a hoptoad handler' do
|
|
6
|
+
it 'uses the api' do
|
|
7
|
+
HoptoadNotifier.should_receive(:notify).with(exception)
|
|
8
|
+
described_class.handle(exception)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
describe Sunspot::Rails::Failover::ExceptionHandlerAdapter do
|
|
13
|
+
describe '.handle' do
|
|
14
|
+
let(:exception) { Exception.new }
|
|
15
|
+
|
|
16
|
+
context 'with exception_handler not set (default)' do
|
|
17
|
+
it_should_behave_like 'a hoptoad handler'
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
context 'with exception_handler set to :hoptoad' do
|
|
21
|
+
before { Sunspot::Rails::Failover.exception_handler = :hoptoad }
|
|
22
|
+
it_should_behave_like 'a hoptoad handler'
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
context 'with exception_handler set to a custom class' do
|
|
26
|
+
before { Sunspot::Rails::Failover.exception_handler = MyExceptionHandler }
|
|
27
|
+
|
|
28
|
+
it 'passes the exception to #handle' do
|
|
29
|
+
MyExceptionHandler.should_receive(:handle).with(exception)
|
|
30
|
+
described_class.handle(exception)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Sunspot::SessionProxy::MasterSlaveWithFailoverSessionProxy do
|
|
4
|
+
let(:master) { Sunspot::Session.new }
|
|
5
|
+
let(:slave) { Sunspot::Session.new }
|
|
6
|
+
let(:proxy) { Sunspot::SessionProxy::MasterSlaveWithFailoverSessionProxy.new(master, slave) }
|
|
7
|
+
|
|
8
|
+
let(:exception_handler_adapter) { Sunspot::Rails::Failover::ExceptionHandlerAdapter }
|
|
9
|
+
|
|
10
|
+
describe '#commit' do
|
|
11
|
+
context 'with no error' do
|
|
12
|
+
it 'calls on the master session' do
|
|
13
|
+
master.should_receive(:commit)
|
|
14
|
+
proxy.commit
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
context 'with an error' do
|
|
19
|
+
it 'passes the exception to the exception handler adapter' do
|
|
20
|
+
exception = Exception.new
|
|
21
|
+
exception_handler_adapter.should_receive(:handle).with(exception)
|
|
22
|
+
master.should_receive(:commit).and_raise(exception)
|
|
23
|
+
proxy.commit
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe '#search' do
|
|
29
|
+
context 'with no error' do
|
|
30
|
+
it 'calls on the slave session' do
|
|
31
|
+
slave.should_receive(:search).and_return(true)
|
|
32
|
+
master.should_not_receive(:search)
|
|
33
|
+
proxy.search
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
context 'with an error on the slave session' do
|
|
38
|
+
it 'calls on the master session' do
|
|
39
|
+
exception = Exception.new
|
|
40
|
+
slave.should_receive(:search).and_raise(exception)
|
|
41
|
+
exception_handler_adapter.should_receive(:handle).with(exception)
|
|
42
|
+
master.should_receive(:search).and_return(true)
|
|
43
|
+
proxy.search
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
context 'with an error on the slave and master sessions' do
|
|
48
|
+
it 'raises the error with no handling' do
|
|
49
|
+
exception = Exception.new
|
|
50
|
+
slave.should_receive(:search).and_raise(exception)
|
|
51
|
+
master.should_receive(:search).and_raise(exception)
|
|
52
|
+
exception_handler_adapter.should_receive(:handle).with(exception).twice
|
|
53
|
+
proxy.should_receive(:raise).with(exception)
|
|
54
|
+
proxy.search
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Sunspot::Rails::Failover do
|
|
4
|
+
describe '.setup' do
|
|
5
|
+
let(:configuration) { double('configuration') }
|
|
6
|
+
|
|
7
|
+
before do
|
|
8
|
+
Sunspot::Rails.stub(:configuration).and_return(configuration)
|
|
9
|
+
configuration.should_receive(:user_configuration_from_key).with('solr', 'url')
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
context 'with a master configuration' do
|
|
13
|
+
before do
|
|
14
|
+
configuration.should_receive(:has_master?).and_return(true)
|
|
15
|
+
configuration.should_receive(:user_configuration_from_key).with('master_solr', 'url')
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it 'sets the session to master/slave with failover support' do
|
|
19
|
+
described_class.setup
|
|
20
|
+
Sunspot.session.should be_an_instance_of(Sunspot::SessionProxy::MasterSlaveWithFailoverSessionProxy)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
context 'with no master configuration' do
|
|
25
|
+
before do
|
|
26
|
+
configuration.should_receive(:has_master?).and_return(false)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it 'sets the session to the default' do
|
|
30
|
+
described_class.setup
|
|
31
|
+
Sunspot.session.should be_an_instance_of(Sunspot::SessionProxy::ThreadLocalSessionProxy)
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
$:.push File.expand_path('../lib', __FILE__)
|
|
3
|
+
require 'sunspot-rails-failover/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = 'sunspot-rails-failover'
|
|
7
|
+
s.version = Sunspot::Rails::Failover::VERSION
|
|
8
|
+
s.platform = Gem::Platform::RUBY
|
|
9
|
+
s.author = 'Justin Ko'
|
|
10
|
+
s.email = 'jko170@gmail.com'
|
|
11
|
+
s.homepage = 'https://github.com/justinko/sunspot-rails-failover'
|
|
12
|
+
s.description = 'Failover support for sunspot_rails'
|
|
13
|
+
s.summary = 'If the Sunspot slave session goes down, reads *and* writes ' \
|
|
14
|
+
'are called upon the master session'
|
|
15
|
+
|
|
16
|
+
s.files = `git ls-files`.split("\n")
|
|
17
|
+
s.test_files = `git ls-files -- spec/*`.split("\n")
|
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
19
|
+
s.require_path = 'lib'
|
|
20
|
+
|
|
21
|
+
s.add_dependency 'sunspot_rails', '~> 1.2.1'
|
|
22
|
+
|
|
23
|
+
s.add_development_dependency 'rspec', '~> 2.5'
|
|
24
|
+
s.add_development_dependency 'hoptoad_notifier'
|
|
25
|
+
end
|
metadata
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
name: sunspot-rails-failover
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease:
|
|
5
|
-
version: 0.0.
|
|
5
|
+
version: 0.0.3
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
8
8
|
- Justin Ko
|
|
@@ -54,8 +54,23 @@ extensions: []
|
|
|
54
54
|
|
|
55
55
|
extra_rdoc_files: []
|
|
56
56
|
|
|
57
|
-
files:
|
|
58
|
-
|
|
57
|
+
files:
|
|
58
|
+
- .gitignore
|
|
59
|
+
- .rvmrc
|
|
60
|
+
- Gemfile
|
|
61
|
+
- LICENSE
|
|
62
|
+
- README.md
|
|
63
|
+
- Rakefile
|
|
64
|
+
- lib/sunspot-rails-failover.rb
|
|
65
|
+
- lib/sunspot-rails-failover/exception_handler_adapter.rb
|
|
66
|
+
- lib/sunspot-rails-failover/master_slave_with_failover_session_proxy.rb
|
|
67
|
+
- lib/sunspot-rails-failover/version.rb
|
|
68
|
+
- spec/spec_helper.rb
|
|
69
|
+
- spec/sunspot-rails-failover/exception_handler_adapter_spec.rb
|
|
70
|
+
- spec/sunspot-rails-failover/master_slave_with_failover_session_proxy_spec.rb
|
|
71
|
+
- spec/sunspot-rails-failover_spec.rb
|
|
72
|
+
- spec/support/my_exception_handler.rb
|
|
73
|
+
- sunspot-rails-failover.gemspec
|
|
59
74
|
has_rdoc: true
|
|
60
75
|
homepage: https://github.com/justinko/sunspot-rails-failover
|
|
61
76
|
licenses: []
|
|
@@ -83,6 +98,10 @@ rubyforge_project:
|
|
|
83
98
|
rubygems_version: 1.6.2
|
|
84
99
|
signing_key:
|
|
85
100
|
specification_version: 3
|
|
86
|
-
summary:
|
|
87
|
-
test_files:
|
|
88
|
-
|
|
101
|
+
summary: If the Sunspot slave session goes down, reads *and* writes are called upon the master session
|
|
102
|
+
test_files:
|
|
103
|
+
- spec/spec_helper.rb
|
|
104
|
+
- spec/sunspot-rails-failover/exception_handler_adapter_spec.rb
|
|
105
|
+
- spec/sunspot-rails-failover/master_slave_with_failover_session_proxy_spec.rb
|
|
106
|
+
- spec/sunspot-rails-failover_spec.rb
|
|
107
|
+
- spec/support/my_exception_handler.rb
|