flying-sphinx 0.6.6 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
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 =