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