flying-sphinx 0.8.5 → 1.0.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.
- data/Gemfile +1 -1
- data/HISTORY +7 -0
- data/flying-sphinx.gemspec +4 -4
- data/lib/flying_sphinx.rb +36 -10
- data/lib/flying_sphinx/action.rb +90 -0
- data/lib/flying_sphinx/api.rb +16 -19
- data/lib/flying_sphinx/binary.rb +7 -0
- data/lib/flying_sphinx/binary/translator.rb +48 -0
- data/lib/flying_sphinx/cli.rb +36 -29
- data/lib/flying_sphinx/configuration.rb +16 -29
- data/lib/flying_sphinx/controller.rb +91 -0
- data/lib/flying_sphinx/rails.rb +1 -11
- data/lib/flying_sphinx/railtie.rb +4 -10
- data/lib/flying_sphinx/setting_files.rb +8 -7
- data/lib/flying_sphinx/sinatra.rb +4 -9
- data/lib/flying_sphinx/sphinxql.rb +7 -0
- data/lib/flying_sphinx/sphinxql/translator.rb +26 -0
- data/lib/flying_sphinx/tasks.rb +5 -8
- data/lib/flying_sphinx/version.rb +1 -1
- data/spec/specs/action_spec.rb +101 -0
- data/spec/specs/api_spec.rb +13 -7
- data/spec/specs/configuration_spec.rb +10 -18
- data/spec/specs/setting_files_spec.rb +27 -31
- metadata +198 -187
- data/lib/flying_sphinx/delayed_delta.rb +0 -89
- data/lib/flying_sphinx/flag_as_deleted_job.rb +0 -41
- data/lib/flying_sphinx/heroku_shared_adapter.rb +0 -5
- data/lib/flying_sphinx/index_request.rb +0 -110
- data/lib/flying_sphinx/sphinx_configuration.rb +0 -30
- data/spec/specs/delayed_delta_spec.rb +0 -147
- data/spec/specs/flag_as_deleted_job_spec.rb +0 -45
- data/spec/specs/index_request_spec.rb +0 -172
- data/spec/specs/sphinx_configuration_spec.rb +0 -42
@@ -0,0 +1,91 @@
|
|
1
|
+
class FlyingSphinx::Controller
|
2
|
+
@index_timeout = 60 * 60 * 3 # 3 hours
|
3
|
+
|
4
|
+
# For backwards compatibility. These aren't actually used here.
|
5
|
+
attr_accessor :path, :bin_path, :searchd_binary_name, :indexer_binary_name
|
6
|
+
|
7
|
+
def self.index_timeout
|
8
|
+
@index_timeout
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.index_timeout=(index_timeout)
|
12
|
+
@index_timeout = index_timeout
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(api)
|
16
|
+
@api = api
|
17
|
+
end
|
18
|
+
|
19
|
+
def configure(file = nil)
|
20
|
+
options = file.nil? ? configuration_options :
|
21
|
+
{:configuration => {'sphinx' => file}, :sphinx_version => '2.0.6'}
|
22
|
+
|
23
|
+
FlyingSphinx::Action.perform api.identifier do
|
24
|
+
api.put 'configure', options
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def index(*indices)
|
29
|
+
options = indices.last.is_a?(Hash) ? indices.pop : {}
|
30
|
+
async = indices.any? && !options[:verbose]
|
31
|
+
options[:indices] = indices.join(',')
|
32
|
+
|
33
|
+
if async
|
34
|
+
api.post 'indices/unique', options
|
35
|
+
else
|
36
|
+
::Delayed::Job.delete_all(
|
37
|
+
"handler LIKE '--- !ruby/object:FlyingSphinx::%'"
|
38
|
+
) if defined?(::Delayed) && ::Delayed::Job.table_exists?
|
39
|
+
|
40
|
+
FlyingSphinx::Action.perform api.identifier, self.class.index_timeout do
|
41
|
+
api.post 'indices', options
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
true
|
46
|
+
end
|
47
|
+
|
48
|
+
def rebuild
|
49
|
+
FlyingSphinx::Action.perform api.identifier, self.class.index_timeout do
|
50
|
+
api.put 'rebuild', configuration_options
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def restart
|
55
|
+
FlyingSphinx::Action.perform api.identifier do
|
56
|
+
api.post 'restart'
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def sphinx_version
|
61
|
+
'2.0.4'
|
62
|
+
end
|
63
|
+
|
64
|
+
def start(options = {})
|
65
|
+
FlyingSphinx::Action.perform(api.identifier) { api.post 'start' }
|
66
|
+
end
|
67
|
+
|
68
|
+
def stop
|
69
|
+
FlyingSphinx::Action.perform(api.identifier) { api.post 'stop' }
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
attr_reader :api
|
75
|
+
|
76
|
+
def configuration_options
|
77
|
+
version = '2.0.4'
|
78
|
+
configuration = ThinkingSphinx::Configuration.instance
|
79
|
+
|
80
|
+
if configuration.respond_to?(:version) && configuration.version.present?
|
81
|
+
version = configuration.version
|
82
|
+
end
|
83
|
+
|
84
|
+
{
|
85
|
+
:sphinx_version => version,
|
86
|
+
:configuration => FlyingSphinx::SettingFiles.new.to_hash.merge(
|
87
|
+
'sphinx' => FlyingSphinx.translator.sphinx_configuration
|
88
|
+
)
|
89
|
+
}
|
90
|
+
end
|
91
|
+
end
|
data/lib/flying_sphinx/rails.rb
CHANGED
@@ -2,16 +2,6 @@ require 'action_controller/dispatcher'
|
|
2
2
|
|
3
3
|
if ENV['FLYING_SPHINX_IDENTIFIER'] || ENV['STAGED_SPHINX_IDENTIFIER']
|
4
4
|
ActionController::Dispatcher.to_prepare :flying_sphinx do
|
5
|
-
|
6
|
-
|
7
|
-
ThinkingSphinx.remote_sphinx = true
|
8
|
-
ThinkingSphinx::Configuration.instance.address = config.host
|
9
|
-
ThinkingSphinx::Configuration.instance.port = config.port
|
10
|
-
ThinkingSphinx::Configuration.instance.configuration.searchd.client_key =
|
11
|
-
config.client_key
|
12
|
-
end
|
13
|
-
|
14
|
-
if ENV['DATABASE_URL'] && ENV['DATABASE_URL'][/^mysql/].nil?
|
15
|
-
ThinkingSphinx.database_adapter = FlyingSphinx::HerokuSharedAdapter
|
5
|
+
FlyingSphinx::Binary.load
|
16
6
|
end
|
17
7
|
end
|
@@ -4,16 +4,10 @@ class FlyingSphinx::Railtie < Rails::Railtie
|
|
4
4
|
end
|
5
5
|
|
6
6
|
initializer "flying_sphinx.set_sphinx_host_and_port" do |app|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
ThinkingSphinx::Configuration.instance.port = config.port
|
12
|
-
ThinkingSphinx::Configuration.instance.configuration.searchd.client_key =
|
13
|
-
config.client_key
|
14
|
-
|
15
|
-
if ENV['DATABASE_URL'] && ENV['DATABASE_URL'][/^mysql/].nil?
|
16
|
-
ThinkingSphinx.database_adapter = FlyingSphinx::HerokuSharedAdapter
|
7
|
+
if ThinkingSphinx::Configuration.instance.respond_to?(:settings)
|
8
|
+
FlyingSphinx::SphinxQL.load
|
9
|
+
else
|
10
|
+
FlyingSphinx::Binary.load
|
17
11
|
end
|
18
12
|
end if ENV['FLYING_SPHINX_IDENTIFIER'] || ENV['STAGED_SPHINX_IDENTIFIER']
|
19
13
|
end
|
@@ -3,17 +3,18 @@ class FlyingSphinx::SettingFiles
|
|
3
3
|
SOURCE_SETTINGS = [:mysql_ssl_cert, :mysql_ssl_key, :mysql_ssl_ca]
|
4
4
|
|
5
5
|
def initialize(indices = nil)
|
6
|
-
@indices = indices ||
|
7
|
-
ThinkingSphinx::Configuration.instance.configuration.indices
|
6
|
+
@indices = indices || FlyingSphinx.translator.sphinx_indices
|
8
7
|
end
|
9
8
|
|
10
|
-
def
|
9
|
+
def to_hash
|
10
|
+
hash = {}
|
11
|
+
|
11
12
|
each_file_for_setting do |setting, file|
|
12
|
-
|
13
|
-
:setting => setting.to_s,
|
14
|
-
:file_name => File.basename(file),
|
15
|
-
:content => File.read(file)
|
13
|
+
hash["#{setting}:#{File.basename(file)}"] = File.read(file)
|
16
14
|
end
|
15
|
+
|
16
|
+
hash['extra'] = hash.keys.join(';')
|
17
|
+
hash
|
17
18
|
end
|
18
19
|
|
19
20
|
private
|
@@ -1,14 +1,9 @@
|
|
1
1
|
require 'flying_sphinx'
|
2
2
|
|
3
3
|
if ENV['FLYING_SPHINX_IDENTIFIER'] || ENV['STAGED_SPHINX_IDENTIFIER']
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
ThinkingSphinx::Configuration.instance.configuration.searchd.client_key =
|
9
|
-
config.client_key
|
10
|
-
|
11
|
-
if ENV['DATABASE_URL'][/^mysql/].nil?
|
12
|
-
ThinkingSphinx.database_adapter = FlyingSphinx::HerokuSharedAdapter
|
4
|
+
if ThinkingSphinx::Configuration.instance.respond_to?(:settings)
|
5
|
+
FlyingSphinx::SphinxQL.load
|
6
|
+
else
|
7
|
+
FlyingSphinx::Binary.load
|
13
8
|
end
|
14
9
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class FlyingSphinx::SphinxQL::Translator
|
2
|
+
def initialize(configuration)
|
3
|
+
thinking_sphinx.controller = FlyingSphinx::Controller.new configuration.api
|
4
|
+
|
5
|
+
thinking_sphinx.settings['connection_options'] = {
|
6
|
+
:host => configuration.host,
|
7
|
+
:port => 9306,
|
8
|
+
:username => configuration.username
|
9
|
+
}
|
10
|
+
end
|
11
|
+
|
12
|
+
def sphinx_configuration
|
13
|
+
@sphinx_configuration ||= thinking_sphinx.render
|
14
|
+
end
|
15
|
+
|
16
|
+
def sphinx_indices
|
17
|
+
sphinx_configuration
|
18
|
+
thinking_sphinx.indices
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def thinking_sphinx
|
24
|
+
ThinkingSphinx::Configuration.instance
|
25
|
+
end
|
26
|
+
end
|
data/lib/flying_sphinx/tasks.rb
CHANGED
@@ -1,29 +1,26 @@
|
|
1
1
|
namespace :fs do
|
2
|
+
desc "Upload Sphinx configuration and process indices"
|
2
3
|
task :index => :environment do
|
3
4
|
FlyingSphinx::CLI.new('setup').run
|
4
5
|
end
|
5
6
|
|
7
|
+
desc "Start the Sphinx daemon on Flying Sphinx servers"
|
6
8
|
task :start => :environment do
|
7
9
|
FlyingSphinx::CLI.new('start').run
|
8
10
|
end
|
9
11
|
|
12
|
+
desc "Stop the Sphinx daemon on Flying Sphinx servers"
|
10
13
|
task :stop => :environment do
|
11
14
|
FlyingSphinx::CLI.new('stop').run
|
12
15
|
end
|
13
16
|
|
17
|
+
desc "Restart the Sphinx daemon on Flying Sphinx servers"
|
14
18
|
task :restart => :environment do
|
15
19
|
FlyingSphinx::CLI.new('restart').run
|
16
20
|
end
|
17
21
|
|
22
|
+
desc "Stop, configure, index and then start Sphinx"
|
18
23
|
task :rebuild => :environment do
|
19
24
|
FlyingSphinx::CLI.new('rebuild').run
|
20
25
|
end
|
21
|
-
|
22
|
-
task :index_log => :environment do
|
23
|
-
FlyingSphinx::IndexRequest.output_last_index
|
24
|
-
end
|
25
|
-
|
26
|
-
task :actions => :environment do
|
27
|
-
FlyingSphinx::Configuration.new.output_recent_actions
|
28
|
-
end
|
29
26
|
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'light_spec_helper'
|
2
|
+
require 'multi_json'
|
3
|
+
require 'flying_sphinx/action'
|
4
|
+
|
5
|
+
describe FlyingSphinx::Action do
|
6
|
+
let(:action) { FlyingSphinx::Action.new 'abc123', 1, &block }
|
7
|
+
let(:block) { Proc.new { response } }
|
8
|
+
let(:socket) { double 'socket', :connect => true, :disconnect => true,
|
9
|
+
:subscribe => true, :[] => channel, :connected => true }
|
10
|
+
let(:channel) { double 'channel', :bind => true }
|
11
|
+
let(:response) { double 'response', :body => body }
|
12
|
+
let(:body) { double 'body', :status => 'OK', :id => 748 }
|
13
|
+
let(:logger) { double 'logger', :debug => true }
|
14
|
+
|
15
|
+
before :each do
|
16
|
+
stub_const 'PusherClient::Socket', double(:new => socket)
|
17
|
+
stub_const 'FlyingSphinx::API::PUSHER_KEY', 'secret'
|
18
|
+
|
19
|
+
FlyingSphinx.stub :logger => logger
|
20
|
+
end
|
21
|
+
|
22
|
+
def perform_and_complete(action)
|
23
|
+
thread = Thread.new { action.perform }
|
24
|
+
sleep 0.01
|
25
|
+
action.send :completion, '{"id":748}'
|
26
|
+
thread.join
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '#perform' do
|
30
|
+
it "sets up a connection to Pusher" do
|
31
|
+
socket.should_receive(:connect)
|
32
|
+
|
33
|
+
perform_and_complete action
|
34
|
+
end
|
35
|
+
|
36
|
+
it "subscribes to the identifier channel" do
|
37
|
+
socket.should_receive(:subscribe).with('abc123')
|
38
|
+
|
39
|
+
perform_and_complete action
|
40
|
+
end
|
41
|
+
|
42
|
+
it "subscribes to debug, completion and failure events" do
|
43
|
+
channel.should_receive(:bind).with('debug').once
|
44
|
+
channel.should_receive(:bind).with('completion').once
|
45
|
+
channel.should_receive(:bind).with('failure').once
|
46
|
+
|
47
|
+
perform_and_complete action
|
48
|
+
end
|
49
|
+
|
50
|
+
it "calls the provided block" do
|
51
|
+
block.should_receive(:call).and_return(response)
|
52
|
+
|
53
|
+
perform_and_complete action
|
54
|
+
end
|
55
|
+
|
56
|
+
it "raises an error if the response's status is BLOCKED" do
|
57
|
+
response.stub :status => 'BLOCKED'
|
58
|
+
|
59
|
+
lambda { action.perform }.should raise_error
|
60
|
+
end
|
61
|
+
|
62
|
+
it "retries the block if it raises an error" do
|
63
|
+
calls = 0
|
64
|
+
action = FlyingSphinx::Action.new 'abc123', 1 do
|
65
|
+
calls += 1
|
66
|
+
raise "Exception" if calls <= 1
|
67
|
+
|
68
|
+
response
|
69
|
+
end
|
70
|
+
|
71
|
+
lambda { perform_and_complete action }.should_not raise_error
|
72
|
+
end
|
73
|
+
|
74
|
+
it "only retries four times" do
|
75
|
+
calls = 0
|
76
|
+
action = FlyingSphinx::Action.new 'abc123', 1 do
|
77
|
+
calls += 1
|
78
|
+
raise "Exception" if calls <= 5
|
79
|
+
|
80
|
+
response
|
81
|
+
end
|
82
|
+
|
83
|
+
lambda { perform_and_complete action }.should raise_error
|
84
|
+
end
|
85
|
+
|
86
|
+
it "logs a warning when the action fails" do
|
87
|
+
logger.should_receive(:warn).with("Action failed.")
|
88
|
+
|
89
|
+
thread = Thread.new { action.perform }
|
90
|
+
sleep 0.01
|
91
|
+
action.send :failure, '{"id":748}'
|
92
|
+
thread.join
|
93
|
+
end
|
94
|
+
|
95
|
+
it "disconnects the socket" do
|
96
|
+
socket.should_receive(:disconnect)
|
97
|
+
|
98
|
+
perform_and_complete action
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
data/spec/specs/api_spec.rb
CHANGED
@@ -7,16 +7,20 @@ describe FlyingSphinx::API do
|
|
7
7
|
let(:faraday) { fire_class_double('Faraday', :new => connection) }
|
8
8
|
let(:adapter) { double('adapter') }
|
9
9
|
let(:connection) { double('connection') }
|
10
|
+
let(:logger) { double :debug => true }
|
11
|
+
let(:response) { double :body => '' }
|
10
12
|
|
11
13
|
before :each do
|
12
14
|
faraday.as_replaced_constant
|
15
|
+
|
16
|
+
FlyingSphinx.stub :logger => logger
|
13
17
|
end
|
14
18
|
|
15
19
|
shared_examples_for 'an API call' do
|
16
20
|
it "sets up a connection with the appropriate headers" do
|
17
21
|
faraday.should_receive(:new) do |options|
|
18
22
|
options[:headers].should == {
|
19
|
-
'Accept' => 'application/vnd.flying-sphinx-
|
23
|
+
'Accept' => 'application/vnd.flying-sphinx-v4+json',
|
20
24
|
'X-Flying-Sphinx-Token' => 'foo:bar',
|
21
25
|
'X-Flying-Sphinx-Version' => FlyingSphinx::Version
|
22
26
|
}
|
@@ -40,10 +44,10 @@ describe FlyingSphinx::API do
|
|
40
44
|
|
41
45
|
describe '#get' do
|
42
46
|
let(:request) { double('request', :url => true) }
|
43
|
-
let(:send_request) { api.get '/resource', 'param' => 'value'}
|
47
|
+
let(:send_request) { api.get '/resource', 'param' => 'value' }
|
44
48
|
|
45
49
|
before :each do
|
46
|
-
connection.stub(:get).and_yield(request)
|
50
|
+
connection.stub(:get).and_yield(request).and_return(response)
|
47
51
|
end
|
48
52
|
|
49
53
|
it_should_behave_like 'an API call'
|
@@ -60,14 +64,15 @@ describe FlyingSphinx::API do
|
|
60
64
|
let(:send_request) { api.post '/resource', 'param' => 'value' }
|
61
65
|
|
62
66
|
before :each do
|
63
|
-
connection.stub(:post =>
|
67
|
+
connection.stub(:post => response)
|
64
68
|
end
|
65
69
|
|
66
70
|
it_should_behave_like 'an API call'
|
67
71
|
|
68
72
|
it "sends the POST request with the given path and data" do
|
69
73
|
connection.should_receive(:post).
|
70
|
-
with('/api/my/app/resource', 'param' => 'value')
|
74
|
+
with('/api/my/app/resource', 'param' => 'value').
|
75
|
+
and_return(response)
|
71
76
|
|
72
77
|
send_request
|
73
78
|
end
|
@@ -77,14 +82,15 @@ describe FlyingSphinx::API do
|
|
77
82
|
let(:send_request) { api.put '/resource', 'param' => 'value' }
|
78
83
|
|
79
84
|
before :each do
|
80
|
-
connection.stub(:put =>
|
85
|
+
connection.stub(:put => response)
|
81
86
|
end
|
82
87
|
|
83
88
|
it_should_behave_like 'an API call'
|
84
89
|
|
85
90
|
it "sends the PUT request with the given path and data" do
|
86
91
|
connection.should_receive(:put).
|
87
|
-
with('/api/my/app/resource', 'param' => 'value')
|
92
|
+
with('/api/my/app/resource', 'param' => 'value').
|
93
|
+
and_return(response)
|
88
94
|
|
89
95
|
send_request
|
90
96
|
end
|
@@ -2,34 +2,26 @@ require 'light_spec_helper'
|
|
2
2
|
require 'flying_sphinx/configuration'
|
3
3
|
|
4
4
|
describe FlyingSphinx::Configuration do
|
5
|
-
let(:api)
|
5
|
+
let(:api) { fire_double('FlyingSphinx::API',
|
6
6
|
:get => double(:body => body, :status => 200)) }
|
7
|
-
let(:body)
|
8
|
-
|
7
|
+
let(:body) { double(:server => 'foo.bar.com', :port => 9319) }
|
8
|
+
let(:api_key) { 'foo-bar-baz' }
|
9
|
+
let(:identifier) { 'my-identifier' }
|
10
|
+
let(:config) { FlyingSphinx::Configuration.new identifier, api_key }
|
9
11
|
|
10
12
|
before :each do
|
11
13
|
fire_class_double('FlyingSphinx::API', :new => api).as_replaced_constant
|
12
14
|
end
|
13
15
|
|
14
|
-
describe '#
|
15
|
-
|
16
|
-
let(:identifier) { 'my-identifier' }
|
17
|
-
let(:config) { FlyingSphinx::Configuration.new identifier, api_key }
|
18
|
-
|
19
|
-
it "sets the host from the API information" do
|
16
|
+
describe '#host' do
|
17
|
+
it "reads the server from the API" do
|
20
18
|
config.host.should == 'foo.bar.com'
|
21
19
|
end
|
20
|
+
end
|
22
21
|
|
23
|
-
|
22
|
+
describe '#port' do
|
23
|
+
it "reads the port from the API" do
|
24
24
|
config.port.should == 9319
|
25
25
|
end
|
26
|
-
|
27
|
-
it "sets the ssh server address" do
|
28
|
-
config.ssh_server.should == 'ssh.bar.com'
|
29
|
-
end
|
30
|
-
|
31
|
-
it "sets the database port" do
|
32
|
-
config.database_port.should == 10319
|
33
|
-
end
|
34
26
|
end
|
35
27
|
end
|