flying-sphinx 0.8.5 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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
- config = FlyingSphinx::Configuration.new
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
- config = FlyingSphinx::Configuration.new
8
-
9
- ThinkingSphinx.remote_sphinx = true
10
- ThinkingSphinx::Configuration.instance.address = config.host
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 upload_to(api)
9
+ def to_hash
10
+ hash = {}
11
+
11
12
  each_file_for_setting do |setting, file|
12
- api.post '/add_file',
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
- config = FlyingSphinx::Configuration.new
5
-
6
- ThinkingSphinx::Configuration.instance.address = config.host
7
- ThinkingSphinx::Configuration.instance.port = config.port
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,7 @@
1
+ module FlyingSphinx::SphinxQL
2
+ def self.load
3
+ require 'flying_sphinx/sphinxql/translator'
4
+
5
+ FlyingSphinx.translator = Translator.new FlyingSphinx::Configuration.new
6
+ end
7
+ 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
@@ -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
@@ -1,3 +1,3 @@
1
1
  module FlyingSphinx
2
- Version = '0.8.5'
2
+ Version = '1.0.0'
3
3
  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
@@ -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-v3+json',
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 => true)
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 => true)
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) { fire_double('FlyingSphinx::API',
5
+ let(:api) { fire_double('FlyingSphinx::API',
6
6
  :get => double(:body => body, :status => 200)) }
7
- let(:body) { double(:server => 'foo.bar.com', :port => 9319,
8
- :ssh_server => 'ssh.bar.com', :database_port => 10319) }
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 '#initialize' do
15
- let(:api_key) { 'foo-bar-baz' }
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
- it "sets the port from the API information" do
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