flying-sphinx 0.6.6 → 0.7.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/HISTORY CHANGED
@@ -1,3 +1,10 @@
1
+ 0.7.0 - 16th July 2012
2
+ * Print the indexing log.
3
+ * Distinguish between search server and SSH/indexing server, which allows for load balancers as the former.
4
+ * Send the gem version through as a header on API calls.
5
+ * Let flying-sphinx.com wrangle the Sphinx configuration.
6
+ * Use v3 of the flying-sphinx.com API
7
+
1
8
  0.6.6 - 14th July 2012
2
9
  * Don't complain about 201s for starting/stopping Sphinx.
3
10
  * Relaxing the faraday_middleware dependency to allow 0.8 releases (Matthew Zikherman).
@@ -25,10 +25,10 @@ Gem::Specification.new do |s|
25
25
  s.add_runtime_dependency 'faraday_middleware', ['~> 0.7']
26
26
  s.add_runtime_dependency 'rash', ['~> 0.3.0']
27
27
 
28
- s.add_development_dependency 'rake', ['0.8.7']
28
+ s.add_development_dependency 'rake', ['~> 0.9.2']
29
+ s.add_development_dependency 'rspec', ['~> 2.11']
30
+ s.add_development_dependency 'rspec-fire', ['~> 1.1.0']
29
31
  s.add_development_dependency 'yajl-ruby', ['~> 0.8.2']
30
- s.add_development_dependency 'rspec', ['~> 2.5.0']
31
- s.add_development_dependency 'rcov', ['~> 0.9.9']
32
32
  s.add_development_dependency 'fakeweb', ['~> 1.3.0']
33
33
  s.add_development_dependency 'fakeweb-matcher', ['~> 1.2.2']
34
34
  s.add_development_dependency 'delayed_job', ['~> 2.1.4']
data/lib/flying_sphinx.rb CHANGED
@@ -2,6 +2,8 @@ module FlyingSphinx
2
2
  #
3
3
  end
4
4
 
5
+ require 'faraday'
6
+ require 'faraday_middleware'
5
7
  require 'net/ssh'
6
8
  require 'riddle/0.9.9'
7
9
 
@@ -11,6 +13,8 @@ require 'flying_sphinx/delayed_delta'
11
13
  require 'flying_sphinx/flag_as_deleted_job'
12
14
  require 'flying_sphinx/heroku_shared_adapter'
13
15
  require 'flying_sphinx/index_request'
16
+ require 'flying_sphinx/setting_files'
17
+ require 'flying_sphinx/sphinx_configuration'
14
18
  require 'flying_sphinx/tunnel'
15
19
  require 'flying_sphinx/version'
16
20
 
@@ -1,14 +1,8 @@
1
- require 'faraday'
2
- require 'faraday_middleware'
3
-
4
1
  class FlyingSphinx::API
5
-
6
- APIServer = 'https://flying-sphinx.com'
7
- APIStagingServer = 'https://staging.flying-sphinx.com'
8
- APIPath = "/api/my/app"
9
- APIVersion = 2
10
-
11
- attr_reader :api_key, :identifier, :adapter
2
+ SERVER = 'https://flying-sphinx.com'
3
+ STAGING_SERVER = 'https://staging.flying-sphinx.com'
4
+ PATH = "/api/my/app"
5
+ VERSION = 3
12
6
 
13
7
  def initialize(identifier, api_key, adapter = Faraday.default_adapter)
14
8
  @api_key = api_key
@@ -38,22 +32,25 @@ class FlyingSphinx::API
38
32
 
39
33
  private
40
34
 
35
+ attr_reader :api_key, :identifier, :adapter
36
+
41
37
  def normalize_path(path)
42
- path = (path == '/' ? nil : "/#{path}")
43
- "#{APIPath}#{path}"
38
+ path = (path == '/' ? '' : "/#{path.gsub(/^\//, '')}")
39
+ "#{PATH}#{path}"
44
40
  end
45
41
 
46
42
  def api_headers
47
43
  {
48
- 'Accept' => "application/vnd.flying-sphinx-v#{APIVersion}+json",
49
- 'X-Flying-Sphinx-Token' => "#{identifier}:#{api_key}"
44
+ 'Accept' => "application/vnd.flying-sphinx-v#{VERSION}+json",
45
+ 'X-Flying-Sphinx-Token' => "#{identifier}:#{api_key}",
46
+ 'X-Flying-Sphinx-Version' => FlyingSphinx::Version
50
47
  }
51
48
  end
52
49
 
53
50
  def connection(connection_options = {})
54
51
  options = {
55
52
  :ssl => {:verify => false},
56
- :url => (ENV['STAGED_SPHINX_API_KEY'] ? APIStagingServer : APIServer),
53
+ :url => (ENV['STAGED_SPHINX_API_KEY'] ? STAGING_SERVER : SERVER),
57
54
  :headers => api_headers
58
55
  }
59
56
 
@@ -1,41 +1,17 @@
1
1
  class FlyingSphinx::Configuration
2
- attr_reader :identifier, :api_key, :host, :port, :database_port, :mem_limit
3
-
4
- FileIndexSettings = [:stopwords, :wordforms, :exceptions]
5
- FileSourceSettings = [:mysql_ssl_cert, :mysql_ssl_key, :mysql_ssl_ca]
6
- FileSettings = FileIndexSettings + FileSourceSettings
2
+ attr_reader :host, :port, :ssh_server, :database_port
7
3
 
8
4
  def initialize(identifier = nil, api_key = nil)
9
5
  @identifier = identifier || identifier_from_env
10
6
  @api_key = api_key || api_key_from_env
11
7
 
12
8
  set_from_server
13
- setup_environment_settings
14
9
  end
15
10
 
16
11
  def api
17
12
  @api ||= FlyingSphinx::API.new(identifier, api_key)
18
13
  end
19
14
 
20
- def sphinx_configuration
21
- thinking_sphinx.generate
22
- set_database_settings
23
- set_file_settings
24
-
25
- riddle.render
26
- end
27
-
28
- def file_setting_pairs(setting)
29
- @file_setting_pairs ||= {}
30
- @file_setting_pairs[setting] ||= begin
31
- pairs = {}
32
- file_setting_sources(setting).each_with_index do |source, index|
33
- pairs[source] = "#{base_path}/#{setting}/#{index}.txt"
34
- end
35
- pairs
36
- end
37
- end
38
-
39
15
  def start_sphinx
40
16
  api.post('start').success?
41
17
  end
@@ -56,14 +32,16 @@ class FlyingSphinx::Configuration
56
32
 
57
33
  private
58
34
 
35
+ attr_reader :identifier, :api_key
36
+
59
37
  def set_from_server
60
38
  response = api.get '/'
61
39
  raise 'Invalid Flying Sphinx credentials' if response.status == 403
62
40
 
63
41
  @host = response.body.server
64
42
  @port = response.body.port
43
+ @ssh_server = response.body.ssh_server
65
44
  @database_port = response.body.database_port
66
- @mem_limit = response.body.mem_limit
67
45
  rescue
68
46
  # If the central Flying Sphinx server is down, let's use the environment
69
47
  # variables so searching is still going to work.
@@ -71,103 +49,6 @@ class FlyingSphinx::Configuration
71
49
  @port = port_from_env
72
50
  end
73
51
 
74
- def base_path
75
- "/mnt/sphinx/flying-sphinx/#{identifier}"
76
- end
77
-
78
- def log_path
79
- "#{base_path}/log"
80
- end
81
-
82
- def thinking_sphinx
83
- ThinkingSphinx::Configuration.instance
84
- end
85
-
86
- def riddle
87
- thinking_sphinx.configuration
88
- end
89
-
90
- def setup_environment_settings
91
- ThinkingSphinx.remote_sphinx = true
92
-
93
- set_searchd_settings
94
- set_indexer_settings
95
- set_path_settings
96
- end
97
-
98
- def set_path_settings
99
- thinking_sphinx.searchd_file_path = "#{base_path}/indexes"
100
-
101
- riddle.searchd.pid_file = "#{base_path}/searchd.pid"
102
- riddle.searchd.log = "#{log_path}/searchd.log"
103
- riddle.searchd.query_log = "#{log_path}/searchd.query.log"
104
- end
105
-
106
- def set_searchd_settings
107
- thinking_sphinx.port = port
108
- thinking_sphinx.address = host
109
-
110
- if riddle.searchd.respond_to?(:client_key)
111
- riddle.searchd.client_key = client_key
112
- end
113
- end
114
-
115
- def set_indexer_settings
116
- riddle.indexer.mem_limit = mem_limit.to_s + 'M'
117
- end
118
-
119
- def set_database_settings
120
- return unless FlyingSphinx::Tunnel.required?
121
-
122
- riddle.indices.each do |index|
123
- next unless index.respond_to?(:sources)
124
-
125
- index.sources.each do |source|
126
- source.sql_host = '127.0.0.1'
127
- source.sql_port = database_port
128
- end
129
- end
130
- end
131
-
132
- def set_file_settings
133
- riddle.indices.each do |index|
134
- set_file_settings_for index, FileIndexSettings
135
-
136
- next unless index.respond_to?(:sources)
137
-
138
- index.sources.each do |source|
139
- set_file_settings_for source, FileSourceSettings
140
- end
141
- end
142
- end
143
-
144
- def set_file_settings_for(object, settings)
145
- settings.each do |setting|
146
- next unless object.respond_to?(setting)
147
- object.send "#{setting}=",
148
- file_setting_pairs(setting)[object.send(setting)]
149
- end
150
- end
151
-
152
- def file_setting_sources(setting)
153
- @file_setting_sources ||= {}
154
- @file_setting_sources[setting] ||= riddle.indices.collect { |index|
155
- file_settings_for_index(index, setting)
156
- }.flatten.compact.uniq
157
- end
158
-
159
- def file_settings_for_index(index, setting)
160
- settings = Array(file_setting_for(index, setting))
161
- settings += index.sources.collect { |source|
162
- file_setting_for(source, setting)
163
- } if index.respond_to?(:sources)
164
- settings
165
- end
166
-
167
- def file_setting_for(object, setting)
168
- object.respond_to?(setting) ? object.send(setting) : nil
169
- end
170
-
171
52
  def identifier_from_env
172
53
  ENV['STAGED_SPHINX_IDENTIFIER'] || ENV['FLYING_SPHINX_IDENTIFIER']
173
54
  end
@@ -2,19 +2,19 @@ class FlyingSphinx::DelayedDelta < ThinkingSphinx::Deltas::DefaultDelta
2
2
  # Adds a job to the queue, if it doesn't already exist. This is to ensure
3
3
  # multiple indexing requests for the same delta index don't get added, as the
4
4
  # index only needs to be processed once.
5
- #
5
+ #
6
6
  # Because indexing jobs are all the same object, they all get serialised to
7
7
  # the same YAML value.
8
- #
8
+ #
9
9
  # @param [Object] object The job, which must respond to the #perform method.
10
10
  # @param [Integer] priority (0)
11
- #
11
+ #
12
12
  def self.enqueue(object, priority = 0)
13
13
  return if duplicates_exist? object
14
-
14
+
15
15
  enqueue_without_duplicates_check object, priority
16
16
  end
17
-
17
+
18
18
  def self.enqueue_without_duplicates_check(object, priority = 0)
19
19
  if defined?(Rails) && Rails.version.to_i <= 2
20
20
  ::Delayed::Job.enqueue(object, priority)
@@ -22,12 +22,12 @@ class FlyingSphinx::DelayedDelta < ThinkingSphinx::Deltas::DefaultDelta
22
22
  ::Delayed::Job.enqueue(object, :priority => priority)
23
23
  end
24
24
  end
25
-
25
+
26
26
  # Checks whether a given job already exists in the queue.
27
- #
27
+ #
28
28
  # @param [Object] object The job
29
29
  # @return [Boolean] True if a duplicate of the job already exists in the queue
30
- #
30
+ #
31
31
  def self.duplicates_exist?(object)
32
32
  ::Delayed::Job.count(
33
33
  :conditions => {
@@ -36,16 +36,16 @@ class FlyingSphinx::DelayedDelta < ThinkingSphinx::Deltas::DefaultDelta
36
36
  }
37
37
  ) > 0
38
38
  end
39
-
39
+
40
40
  # Adds a job to the queue for processing the given model's delta index. A job
41
41
  # for hiding the instance in the core index is also created, if an instance is
42
42
  # provided.
43
- #
44
- # Neither job will be queued if updates or deltas are disabled, or if the
43
+ #
44
+ # Neither job will be queued if updates or deltas are disabled, or if the
45
45
  # instance (when given) is not toggled to be in the delta index. The first two
46
46
  # options are controlled via ThinkingSphinx.updates_enabled? and
47
47
  # ThinkingSphinx.deltas_enabled?.
48
- #
48
+ #
49
49
  # @param [Class] model the ActiveRecord model to index.
50
50
  # @param [ActiveRecord::Base] instance the instance of the given model that
51
51
  # has changed. Optional.
@@ -53,38 +53,34 @@ class FlyingSphinx::DelayedDelta < ThinkingSphinx::Deltas::DefaultDelta
53
53
  #
54
54
  def index(model, instance = nil)
55
55
  return true if skip? instance
56
-
56
+
57
57
  self.class.enqueue(
58
58
  FlyingSphinx::IndexRequest.new(model.delta_index_names),
59
59
  delayed_job_priority
60
60
  )
61
-
61
+
62
62
  self.class.enqueue_without_duplicates_check(
63
63
  FlyingSphinx::FlagAsDeletedJob.new(
64
64
  model.core_index_names, instance.sphinx_document_id
65
65
  ),
66
66
  delayed_job_priority
67
67
  ) if instance
68
-
68
+
69
69
  true
70
70
  end
71
-
71
+
72
72
  private
73
-
74
- def config
75
- @config ||= ThinkingSphinx::Configuration.instance
76
- end
77
-
73
+
78
74
  def delayed_job_priority
79
- config.delayed_job_priority
75
+ ThinkingSphinx::Configuration.instance.delayed_job_priority
80
76
  end
81
-
77
+
82
78
  # Checks whether jobs should be enqueued. Only true if updates and deltas are
83
79
  # enabled, and the instance (if there is one) is toggled.
84
- #
80
+ #
85
81
  # @param [ActiveRecord::Base, NilClass] instance
86
82
  # @return [Boolean]
87
- #
83
+ #
88
84
  def skip?(instance)
89
85
  !ThinkingSphinx.updates_enabled? ||
90
86
  !ThinkingSphinx.deltas_enabled? ||
@@ -29,8 +29,9 @@ class FlyingSphinx::IndexRequest
29
29
  end
30
30
 
31
31
  def update_and_index
32
- update_sphinx_configuration
33
- update_sphinx_reference_files
32
+ FlyingSphinx::SphinxConfiguration.new.upload_to api, tunnel?
33
+ FlyingSphinx::SettingFiles.new.upload_to api
34
+
34
35
  index
35
36
  end
36
37
 
@@ -40,7 +41,7 @@ class FlyingSphinx::IndexRequest
40
41
  status = request_status
41
42
  case status
42
43
  when 'FINISHED'
43
- 'Index Request has completed.'
44
+ "Index Request has completed:\n#{request_log}"
44
45
  when 'FAILED'
45
46
  'Index Request failed.'
46
47
  when 'PENDING'
@@ -66,25 +67,8 @@ class FlyingSphinx::IndexRequest
66
67
  @configuration ||= FlyingSphinx::Configuration.new
67
68
  end
68
69
 
69
- def update_sphinx_configuration
70
- api.put '/',
71
- :configuration => configuration.sphinx_configuration,
72
- :sphinx_version => ThinkingSphinx::Configuration.instance.version
73
- end
74
-
75
- def update_sphinx_reference_files
76
- FlyingSphinx::Configuration::FileSettings.each do |setting|
77
- configuration.file_setting_pairs(setting).each do |local, remote|
78
- api.post '/add_file',
79
- :setting => setting.to_s,
80
- :file_name => remote.split('/').last,
81
- :content => open(local).read
82
- end
83
- end
84
- end
85
-
86
70
  def index
87
- if FlyingSphinx::Tunnel.required?
71
+ if tunnel?
88
72
  tunnelled_index
89
73
  else
90
74
  direct_index
@@ -136,8 +120,17 @@ class FlyingSphinx::IndexRequest
136
120
  end
137
121
  end
138
122
 
123
+ def request_log
124
+ @request.log
125
+ end
126
+
139
127
  def request_status
140
- api.get("indices/#{index_id}").body.status
128
+ @request = api.get("indices/#{index_id}").body
129
+ @request.status
130
+ end
131
+
132
+ def tunnel?
133
+ FlyingSphinx::Tunnel.required?
141
134
  end
142
135
 
143
136
  def cancel_request
@@ -4,6 +4,7 @@ if ENV['FLYING_SPHINX_IDENTIFIER'] || ENV['STAGED_SPHINX_IDENTIFIER']
4
4
  ActionController::Dispatcher.to_prepare :flying_sphinx do
5
5
  config = FlyingSphinx::Configuration.new
6
6
 
7
+ ThinkingSphinx.remote_sphinx = true
7
8
  ThinkingSphinx::Configuration.instance.address = config.host
8
9
  ThinkingSphinx::Configuration.instance.port = config.port
9
10
  ThinkingSphinx::Configuration.instance.configuration.searchd.client_key =
@@ -6,6 +6,7 @@ class FlyingSphinx::Railtie < Rails::Railtie
6
6
  initializer "flying_sphinx.set_sphinx_host_and_port" do |app|
7
7
  config = FlyingSphinx::Configuration.new
8
8
 
9
+ ThinkingSphinx.remote_sphinx = true
9
10
  ThinkingSphinx::Configuration.instance.address = config.host
10
11
  ThinkingSphinx::Configuration.instance.port = config.port
11
12
  ThinkingSphinx::Configuration.instance.configuration.searchd.client_key =