namxam-ts-delayed-delta 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.textile +54 -0
- data/features/delayed_deltas.feature +37 -0
- data/features/step_definitions/common_steps.rb +48 -0
- data/features/step_definitions/delayed_delta_steps.rb +7 -0
- data/features/support/database.example.yml +3 -0
- data/features/support/db/fixtures/delayed_betas.rb +10 -0
- data/features/support/db/migrations/create_delayed_betas.rb +17 -0
- data/features/support/env.rb +17 -0
- data/features/support/models/delayed_beta.rb +7 -0
- data/lib/thinking_sphinx/deltas/delayed_delta.rb +64 -0
- data/lib/thinking_sphinx/deltas/delayed_delta/delta_job.rb +27 -0
- data/lib/thinking_sphinx/deltas/delayed_delta/flag_as_deleted_job.rb +40 -0
- data/lib/thinking_sphinx/deltas/delayed_delta/job.rb +54 -0
- data/lib/thinking_sphinx/deltas/delayed_delta/tasks.rb +21 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/thinking_sphinx/deltas/delayed_delta/delta_job_spec.rb +46 -0
- data/spec/thinking_sphinx/deltas/delayed_delta/flag_as_deleted_job_spec.rb +78 -0
- data/spec/thinking_sphinx/deltas/delayed_delta/job_spec.rb +52 -0
- data/spec/thinking_sphinx/deltas/delayed_delta_spec.rb +128 -0
- metadata +148 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Pat Allan
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.textile
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
h1. Delayed Deltas for Thinking Sphinx
|
2
|
+
|
3
|
+
h2. Installation
|
4
|
+
|
5
|
+
You'll need Thinking Sphinx 1.3.0 or later, and Delayed Job as well. The latter is flagged as a dependency.
|
6
|
+
|
7
|
+
<pre><code>gem install ts-delayed-delta --source http://gemcutter.org</code></pre>
|
8
|
+
|
9
|
+
In your @environment.rb@ file, with the rest of your gem dependencies:
|
10
|
+
|
11
|
+
<pre><code>config.gem 'ts-delayed-delta',
|
12
|
+
:lib => 'thinking_sphinx/deltas/delayed_delta'
|
13
|
+
:version => '>= 1.0.0',
|
14
|
+
:source => 'http://gemcutter.org'</code></pre>
|
15
|
+
|
16
|
+
And add the following line to the bottom of your @Rakefile@:
|
17
|
+
|
18
|
+
<pre><code>require 'thinking_sphinx/deltas/delayed_delta/tasks'</code></pre>
|
19
|
+
|
20
|
+
If this is your first time running Delayed Job, then you're going to need the jobs table migration as well:
|
21
|
+
|
22
|
+
<pre><code>script/generate delayed_job</code></pre>
|
23
|
+
|
24
|
+
For the indexes you want to use this delta approach, make sure you set that up in their @define_index@ blocks.
|
25
|
+
|
26
|
+
<pre><code>define_index do
|
27
|
+
# ...
|
28
|
+
|
29
|
+
set_property :delta => :delayed
|
30
|
+
end</code></pre>
|
31
|
+
|
32
|
+
If you've never used delta indexes before, you'll want to add the boolean column named delta to each model that is using the approach.
|
33
|
+
|
34
|
+
<pre><code>def self.up
|
35
|
+
add_column :articles, :delta, :boolean, :default => true, :null => false
|
36
|
+
end</code></pre>
|
37
|
+
|
38
|
+
h2. Usage
|
39
|
+
|
40
|
+
Once you've got it all set up, all you need to do is make sure that the delayed job process is running - either by Delayed Job's built-in approach, or Thinking Sphinx's custom rake task:
|
41
|
+
|
42
|
+
<pre><code>rake thinking_sphinx:delayed_delta</code></pre>
|
43
|
+
|
44
|
+
There's also a short name for the same task, to save your fingers some effort:
|
45
|
+
|
46
|
+
<pre><code>rake ts:dd</code></pre>
|
47
|
+
|
48
|
+
h2. Contributors
|
49
|
+
|
50
|
+
* "Ryan Schlesinger":http://github.com/ryansch
|
51
|
+
|
52
|
+
h2. Copyright
|
53
|
+
|
54
|
+
Copyright (c) 2009 Pat Allan, and released under an MIT Licence.
|
@@ -0,0 +1,37 @@
|
|
1
|
+
Feature: Delayed Delta Indexing
|
2
|
+
In order to have delta indexing on frequently-updated sites
|
3
|
+
Developers
|
4
|
+
Should be able to use delayed_job to handle delta indexes to lower system load
|
5
|
+
|
6
|
+
Scenario: Delta Index should not fire automatically
|
7
|
+
Given Sphinx is running
|
8
|
+
And I am searching on delayed betas
|
9
|
+
When I search for one
|
10
|
+
Then I should get 1 result
|
11
|
+
|
12
|
+
When I change the name of delayed beta one to eleven
|
13
|
+
And I wait for Sphinx to catch up
|
14
|
+
And I search for one
|
15
|
+
Then I should get 1 result
|
16
|
+
|
17
|
+
When I search for eleven
|
18
|
+
Then I should get 0 results
|
19
|
+
|
20
|
+
Scenario: Delta Index should fire when jobs are run
|
21
|
+
Given Sphinx is running
|
22
|
+
And I am searching on delayed betas
|
23
|
+
When I search for one
|
24
|
+
Then I should get 1 result
|
25
|
+
|
26
|
+
When I change the name of delayed beta two to twelve
|
27
|
+
And I wait for Sphinx to catch up
|
28
|
+
And I search for twelve
|
29
|
+
Then I should get 0 results
|
30
|
+
|
31
|
+
When I run the delayed jobs
|
32
|
+
And I wait for Sphinx to catch up
|
33
|
+
And I search for twelve
|
34
|
+
Then I should get 1 result
|
35
|
+
|
36
|
+
When I search for two
|
37
|
+
Then I should get 0 results
|
@@ -0,0 +1,48 @@
|
|
1
|
+
Before do
|
2
|
+
$queries_executed = []
|
3
|
+
ThinkingSphinx::Deltas::Job.cancel_thinking_sphinx_jobs
|
4
|
+
|
5
|
+
@model = nil
|
6
|
+
@method = :search
|
7
|
+
@query = ""
|
8
|
+
@conditions = {}
|
9
|
+
@with = {}
|
10
|
+
@without = {}
|
11
|
+
@with_all = {}
|
12
|
+
@options = {}
|
13
|
+
@results = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
Given "Sphinx is running" do
|
17
|
+
ThinkingSphinx::Configuration.instance.controller.should be_running
|
18
|
+
end
|
19
|
+
|
20
|
+
Given /^I am searching on (.+)$/ do |model|
|
21
|
+
@model = model.gsub(/\s/, '_').singularize.camelize.constantize
|
22
|
+
end
|
23
|
+
|
24
|
+
When "I wait for Sphinx to catch up" do
|
25
|
+
sleep(0.25)
|
26
|
+
end
|
27
|
+
|
28
|
+
When /^I search for (\w+)$/ do |query|
|
29
|
+
@results = nil
|
30
|
+
@query = query
|
31
|
+
end
|
32
|
+
|
33
|
+
Then /^I should get (\d+) results?$/ do |count|
|
34
|
+
results.length.should == count.to_i
|
35
|
+
end
|
36
|
+
|
37
|
+
def results
|
38
|
+
@results ||= (@model || ThinkingSphinx).send(
|
39
|
+
@method,
|
40
|
+
@query,
|
41
|
+
@options.merge(
|
42
|
+
:conditions => @conditions,
|
43
|
+
:with => @with,
|
44
|
+
:without => @without,
|
45
|
+
:with_all => @with_all
|
46
|
+
)
|
47
|
+
)
|
48
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
DelayedBeta.create :name => "one"
|
2
|
+
DelayedBeta.create :name => "two"
|
3
|
+
DelayedBeta.create :name => "three"
|
4
|
+
DelayedBeta.create :name => "four"
|
5
|
+
DelayedBeta.create :name => "five"
|
6
|
+
DelayedBeta.create :name => "six"
|
7
|
+
DelayedBeta.create :name => "seven"
|
8
|
+
DelayedBeta.create :name => "eight"
|
9
|
+
DelayedBeta.create :name => "nine"
|
10
|
+
DelayedBeta.create :name => "ten"
|
@@ -0,0 +1,17 @@
|
|
1
|
+
ActiveRecord::Base.connection.create_table :delayed_betas, :force => true do |t|
|
2
|
+
t.column :name, :string, :null => false
|
3
|
+
t.column :delta, :boolean, :null => false, :default => false
|
4
|
+
end
|
5
|
+
|
6
|
+
ActiveRecord::Base.connection.create_table :delayed_jobs, :force => true do |t|
|
7
|
+
t.column :priority, :integer, :default => 0
|
8
|
+
t.column :attempts, :integer, :default => 0
|
9
|
+
t.column :handler, :text
|
10
|
+
t.column :last_error, :string
|
11
|
+
t.column :run_at, :datetime
|
12
|
+
t.column :locked_at, :datetime
|
13
|
+
t.column :failed_at, :datetime
|
14
|
+
t.column :locked_by, :string
|
15
|
+
t.column :created_at, :datetime
|
16
|
+
t.column :updated_at, :datetime
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'cucumber'
|
3
|
+
require 'spec/expectations'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'active_record'
|
6
|
+
|
7
|
+
$:.unshift File.dirname(__FILE__) + '/../../lib'
|
8
|
+
|
9
|
+
require 'cucumber/thinking_sphinx/internal_world'
|
10
|
+
|
11
|
+
world = Cucumber::ThinkingSphinx::InternalWorld.new
|
12
|
+
world.configure_database
|
13
|
+
|
14
|
+
require "thinking_sphinx"
|
15
|
+
require 'thinking_sphinx/deltas/delayed_delta'
|
16
|
+
|
17
|
+
world.setup
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'delayed_job'
|
2
|
+
require 'thinking_sphinx'
|
3
|
+
require 'thinking_sphinx/deltas/delayed_delta/delta_job'
|
4
|
+
require 'thinking_sphinx/deltas/delayed_delta/flag_as_deleted_job'
|
5
|
+
require 'thinking_sphinx/deltas/delayed_delta/job'
|
6
|
+
|
7
|
+
# Delayed Deltas for Thinking Sphinx, using Delayed Job.
|
8
|
+
#
|
9
|
+
# This documentation is aimed at those reading the code. If you're looking for
|
10
|
+
# a guide to Thinking Sphinx and/or deltas, I recommend you start with the
|
11
|
+
# Thinking Sphinx site instead - or the README for this library at the very
|
12
|
+
# least.
|
13
|
+
#
|
14
|
+
# @author Patrick Allan
|
15
|
+
# @see http://ts.freelancing-gods.com Thinking Sphinx
|
16
|
+
#
|
17
|
+
class ThinkingSphinx::Deltas::DelayedDelta < ThinkingSphinx::Deltas::DefaultDelta
|
18
|
+
|
19
|
+
# Adds a job to the queue for processing the given model's delta index. A job
|
20
|
+
# for hiding the instance in the core index is also created, if an instance is
|
21
|
+
# provided.
|
22
|
+
#
|
23
|
+
# Neither job will be queued if updates or deltas are disabled, or if the
|
24
|
+
# instance (when given) is not toggled to be in the delta index. The first two
|
25
|
+
# options are controlled via ThinkingSphinx.updates_enabled? and
|
26
|
+
# ThinkingSphinx.deltas_enabled?.
|
27
|
+
#
|
28
|
+
# @param [Class] model the ActiveRecord model to index.
|
29
|
+
# @param [ActiveRecord::Base] instance the instance of the given model that
|
30
|
+
# has changed. Optional.
|
31
|
+
# @return [Boolean] true
|
32
|
+
#
|
33
|
+
def index(model, instance = nil)
|
34
|
+
return true if skip? instance
|
35
|
+
|
36
|
+
ThinkingSphinx::Deltas::Job.enqueue(
|
37
|
+
ThinkingSphinx::Deltas::DeltaJob.new(model.delta_index_names),
|
38
|
+
ThinkingSphinx::Configuration.instance.delayed_job_priority
|
39
|
+
)
|
40
|
+
|
41
|
+
Delayed::Job.enqueue(
|
42
|
+
ThinkingSphinx::Deltas::FlagAsDeletedJob.new(
|
43
|
+
model.core_index_names, instance.sphinx_document_id
|
44
|
+
),
|
45
|
+
ThinkingSphinx::Configuration.instance.delayed_job_priority
|
46
|
+
) if instance
|
47
|
+
|
48
|
+
true
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
# Checks whether jobs should be enqueued. Only true if updates and deltas are
|
54
|
+
# enabled, and the instance (if there is one) is toggled.
|
55
|
+
#
|
56
|
+
# @param [ActiveRecord::Base, NilClass] instance
|
57
|
+
# @return [Boolean]
|
58
|
+
#
|
59
|
+
def skip?(instance)
|
60
|
+
!ThinkingSphinx.updates_enabled? ||
|
61
|
+
!ThinkingSphinx.deltas_enabled? ||
|
62
|
+
(instance && !toggled(instance))
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# A simple job class that processes a given index.
|
2
|
+
#
|
3
|
+
class ThinkingSphinx::Deltas::DeltaJob
|
4
|
+
attr_accessor :indexes
|
5
|
+
|
6
|
+
# Initialises the object with an index name.
|
7
|
+
#
|
8
|
+
# @param [String] index the name of the Sphinx index
|
9
|
+
#
|
10
|
+
def initialize(indexes)
|
11
|
+
@indexes = indexes
|
12
|
+
end
|
13
|
+
|
14
|
+
# Runs Sphinx's indexer tool to process the index. Currently assumes Sphinx is
|
15
|
+
# running.
|
16
|
+
#
|
17
|
+
# @return [Boolean] true
|
18
|
+
#
|
19
|
+
def perform
|
20
|
+
config = ThinkingSphinx::Configuration.instance
|
21
|
+
|
22
|
+
output = `#{config.bin_path}#{config.indexer_binary_name} --config #{config.config_file} --rotate #{indexes.join(' ')}`
|
23
|
+
puts output unless ThinkingSphinx.suppress_delta_output?
|
24
|
+
|
25
|
+
true
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# A simple job for flagging a specified Sphinx document in a given index as
|
2
|
+
# 'deleted'.
|
3
|
+
#
|
4
|
+
class ThinkingSphinx::Deltas::FlagAsDeletedJob
|
5
|
+
attr_accessor :indexes, :document_id
|
6
|
+
|
7
|
+
# Initialises the object with an index name and document id. Please note that
|
8
|
+
# the document id is Sphinx's unique identifier, and will almost certainly not
|
9
|
+
# be the model instance's primary key value.
|
10
|
+
#
|
11
|
+
# @param [String] index The index name
|
12
|
+
# @param [Integer] document_id The document id
|
13
|
+
#
|
14
|
+
def initialize(indexes, document_id)
|
15
|
+
@indexes, @document_id = indexes, document_id
|
16
|
+
end
|
17
|
+
|
18
|
+
# Updates the sphinx_deleted attribute for the given document, setting the
|
19
|
+
# value to 1 (true). This is not a special attribute in Sphinx, but is used
|
20
|
+
# by Thinking Sphinx to ignore deleted values between full re-indexing. It's
|
21
|
+
# particularly useful in this situation to avoid old values in the core index
|
22
|
+
# and just use the new values in the delta index as a reference point.
|
23
|
+
#
|
24
|
+
# @return [Boolean] true
|
25
|
+
#
|
26
|
+
def perform
|
27
|
+
config = ThinkingSphinx::Configuration.instance
|
28
|
+
|
29
|
+
indexes.each do |index|
|
30
|
+
config.client.update(
|
31
|
+
index,
|
32
|
+
['sphinx_deleted'],
|
33
|
+
{@document_id => [1]}
|
34
|
+
) if ThinkingSphinx.sphinx_running? &&
|
35
|
+
ThinkingSphinx.search_for_id(@document_id, index)
|
36
|
+
end
|
37
|
+
|
38
|
+
true
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# A custom job model, subclassed from Delayed::Job. The two things it does
|
2
|
+
# differently is that it checks for duplicate tasks before enqueuing them, and
|
3
|
+
# provides the option to remove all Delayed Delta jobs from the queue.
|
4
|
+
#
|
5
|
+
# As such, this class should not be used for any other tasks.
|
6
|
+
#
|
7
|
+
class ThinkingSphinx::Deltas::Job < Delayed::Job
|
8
|
+
# Adds a job to the queue, if it doesn't already exist. This is to ensure
|
9
|
+
# multiple indexing requests for the same delta index don't get added, as the
|
10
|
+
# index only needs to be processed once.
|
11
|
+
#
|
12
|
+
# Because indexing jobs are all the same object, with a single instance
|
13
|
+
# variable (the index name), they all get serialised to the same YAML value.
|
14
|
+
#
|
15
|
+
# @param [Object] object The job, which must respond to the #perform method.
|
16
|
+
# @param [Integer] priority (0)
|
17
|
+
#
|
18
|
+
def self.enqueue(object, priority = 0)
|
19
|
+
::Delayed::Job.enqueue(object, priority) unless duplicates_exist(object)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Remove all Thinking Sphinx/Delayed Delta jobs from the queue. If the
|
23
|
+
# delayed_jobs table does not exist, this method will do nothing.
|
24
|
+
#
|
25
|
+
def self.cancel_thinking_sphinx_jobs
|
26
|
+
if connection.tables.include?("delayed_jobs")
|
27
|
+
delete_all("handler LIKE '--- !ruby/object:ThinkingSphinx::Deltas::%'")
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# This is to stop ActiveRecord complaining about a missing database when
|
32
|
+
# running specs (otherwise printing failure messages raises confusing stack
|
33
|
+
# traces).
|
34
|
+
#
|
35
|
+
def self.inspect
|
36
|
+
"Job"
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# Checks whether a given job already exists in the queue.
|
42
|
+
#
|
43
|
+
# @param [Object] object The job
|
44
|
+
# @return [Boolean] True if a duplicate of the job already exists in the queue
|
45
|
+
#
|
46
|
+
def self.duplicates_exist(object)
|
47
|
+
count(
|
48
|
+
:conditions => {
|
49
|
+
:handler => object.to_yaml,
|
50
|
+
:locked_at => nil
|
51
|
+
}
|
52
|
+
) > 0
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
namespace :thinking_sphinx do
|
2
|
+
task :index do
|
3
|
+
ThinkingSphinx::Deltas::Job.cancel_thinking_sphinx_jobs
|
4
|
+
end
|
5
|
+
|
6
|
+
desc "Process stored delta index requests"
|
7
|
+
task :delayed_delta => :app_env do
|
8
|
+
require 'delayed/worker'
|
9
|
+
require 'thinking_sphinx/deltas/delayed_delta'
|
10
|
+
|
11
|
+
Delayed::Worker.new(
|
12
|
+
:min_priority => ENV['MIN_PRIORITY'],
|
13
|
+
:max_priority => ENV['MAX_PRIORITY']
|
14
|
+
).start
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
namespace :ts do
|
19
|
+
desc "Process stored delta index requests"
|
20
|
+
task :dd => "thinking_sphinx:delayed_delta"
|
21
|
+
end
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'spec'
|
5
|
+
require 'spec/autorun'
|
6
|
+
|
7
|
+
require 'thinking_sphinx'
|
8
|
+
require 'thinking_sphinx/deltas/delayed_delta'
|
9
|
+
|
10
|
+
Spec::Runner.configure do |config|
|
11
|
+
#
|
12
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe ThinkingSphinx::Deltas::DeltaJob do
|
4
|
+
describe '#perform' do
|
5
|
+
before :each do
|
6
|
+
ThinkingSphinx.suppress_delta_output = false
|
7
|
+
|
8
|
+
@delta_job = ThinkingSphinx::Deltas::DeltaJob.new(['foo_core'])
|
9
|
+
@delta_job.stub! :` => true
|
10
|
+
@delta_job.stub! :puts => nil
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should output the delta indexing by default" do
|
14
|
+
@delta_job.should_receive(:puts)
|
15
|
+
|
16
|
+
@delta_job.perform
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should not output the delta indexing if requested" do
|
20
|
+
ThinkingSphinx.suppress_delta_output = true
|
21
|
+
@delta_job.should_not_receive(:puts)
|
22
|
+
|
23
|
+
@delta_job.perform
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should process just the requested indexes" do
|
27
|
+
@delta_job.should_receive(:`) do |command|
|
28
|
+
command.should match(/foo_core/)
|
29
|
+
command.should_not match(/--all/)
|
30
|
+
end
|
31
|
+
|
32
|
+
@delta_job.perform
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'multiple indexes' do
|
36
|
+
it "should process all requested indexes" do
|
37
|
+
@delta_job.indexes = ['foo_core', 'bar_core']
|
38
|
+
@delta_job.should_receive(:`) do |command|
|
39
|
+
command.should match(/foo_core bar_core/)
|
40
|
+
end
|
41
|
+
|
42
|
+
@delta_job.perform
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe ThinkingSphinx::Deltas::FlagAsDeletedJob do
|
4
|
+
describe '#perform' do
|
5
|
+
before :each do
|
6
|
+
ThinkingSphinx.updates_enabled = true
|
7
|
+
@client = stub('client', :update => true)
|
8
|
+
|
9
|
+
ThinkingSphinx::Configuration.instance.stub!(:client => @client)
|
10
|
+
ThinkingSphinx.stub!(:search_for_id => true)
|
11
|
+
ThinkingSphinx.stub!(:sphinx_running? => true)
|
12
|
+
|
13
|
+
@job = ThinkingSphinx::Deltas::FlagAsDeletedJob.new(['foo_core'], 12)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should not update if Sphinx isn't running" do
|
17
|
+
ThinkingSphinx.stub!(:sphinx_running? => false)
|
18
|
+
@client.should_not_receive(:update)
|
19
|
+
|
20
|
+
@job.perform
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should not update if the document isn't in the index" do
|
24
|
+
ThinkingSphinx.stub!(:search_for_id => false)
|
25
|
+
@client.should_not_receive(:update)
|
26
|
+
|
27
|
+
@job.perform
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should update the specified index" do
|
31
|
+
@client.should_receive(:update) do |index, attributes, values|
|
32
|
+
index.should == 'foo_core'
|
33
|
+
end
|
34
|
+
|
35
|
+
@job.perform
|
36
|
+
end
|
37
|
+
|
38
|
+
it "should update all specified indexes" do
|
39
|
+
@job.indexes = ['foo_core', 'bar_core']
|
40
|
+
@client.should_receive(:update).with('foo_core', anything, anything)
|
41
|
+
@client.should_receive(:update).with('bar_core', anything, anything)
|
42
|
+
|
43
|
+
@job.perform
|
44
|
+
end
|
45
|
+
|
46
|
+
it "should update the sphinx_deleted attribute" do
|
47
|
+
@client.should_receive(:update) do |index, attributes, values|
|
48
|
+
attributes.should == ['sphinx_deleted']
|
49
|
+
end
|
50
|
+
|
51
|
+
@job.perform
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should set sphinx_deleted for the given document to true" do
|
55
|
+
@client.should_receive(:update) do |index, attributes, values|
|
56
|
+
values[12].should == [1]
|
57
|
+
end
|
58
|
+
|
59
|
+
@job.perform
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should check for the existence of the document in the specified index" do
|
63
|
+
ThinkingSphinx.should_receive(:search_for_id) do |id, index|
|
64
|
+
index.should == 'foo_core'
|
65
|
+
end
|
66
|
+
|
67
|
+
@job.perform
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should check for the existence of the given document id" do
|
71
|
+
ThinkingSphinx.should_receive(:search_for_id) do |id, index|
|
72
|
+
id.should == 12
|
73
|
+
end
|
74
|
+
|
75
|
+
@job.perform
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe ThinkingSphinx::Deltas::Job do
|
4
|
+
describe '.enqueue' do
|
5
|
+
before :each do
|
6
|
+
ThinkingSphinx::Deltas::Job.stub!(:count => 0)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should enqueue if there's no existing jobs for the same index" do
|
10
|
+
Delayed::Job.should_receive(:enqueue)
|
11
|
+
|
12
|
+
ThinkingSphinx::Deltas::Job.enqueue(stub('object'))
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should not enqueue the job if there's an existing job already" do
|
16
|
+
ThinkingSphinx::Deltas::Job.stub!(:count => 1)
|
17
|
+
Delayed::Job.should_not_receive(:enqueue)
|
18
|
+
|
19
|
+
ThinkingSphinx::Deltas::Job.enqueue(stub('object'))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '.cancel_thinking_sphinx_jobs' do
|
24
|
+
before :each do
|
25
|
+
ThinkingSphinx::Deltas::Job.stub!(:connection, stub('connection'))
|
26
|
+
ThinkingSphinx::Deltas::Job.stub!(:delete_all => true)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should not delete any rows if the delayed_jobs table does not exist" do
|
30
|
+
ThinkingSphinx::Deltas::Job.connection.stub!(:tables => [])
|
31
|
+
ThinkingSphinx::Deltas::Job.should_not_receive(:delete_all)
|
32
|
+
|
33
|
+
ThinkingSphinx::Deltas::Job.cancel_thinking_sphinx_jobs
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should delete rows if the delayed_jobs table does exist" do
|
37
|
+
ThinkingSphinx::Deltas::Job.connection.stub!(:tables => ['delayed_jobs'])
|
38
|
+
ThinkingSphinx::Deltas::Job.should_receive(:delete_all)
|
39
|
+
|
40
|
+
ThinkingSphinx::Deltas::Job.cancel_thinking_sphinx_jobs
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should delete only Thinking Sphinx jobs" do
|
44
|
+
ThinkingSphinx::Deltas::Job.connection.stub!(:tables => ['delayed_jobs'])
|
45
|
+
ThinkingSphinx::Deltas::Job.should_receive(:delete_all) do |sql|
|
46
|
+
sql.should match(/handler LIKE '--- !ruby\/object:ThinkingSphinx::Deltas::\%'/)
|
47
|
+
end
|
48
|
+
|
49
|
+
ThinkingSphinx::Deltas::Job.cancel_thinking_sphinx_jobs
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'spec/spec_helper'
|
2
|
+
|
3
|
+
describe ThinkingSphinx::Deltas::DelayedDelta do
|
4
|
+
describe '#index' do
|
5
|
+
before :each do
|
6
|
+
ThinkingSphinx.updates_enabled = true
|
7
|
+
ThinkingSphinx.deltas_enabled = true
|
8
|
+
ThinkingSphinx::Configuration.instance.delayed_job_priority = 2
|
9
|
+
|
10
|
+
ThinkingSphinx::Deltas::Job.stub!(:enqueue => true)
|
11
|
+
Delayed::Job.stub!(:enqueue => true, :inspect => "Delayed::Job")
|
12
|
+
|
13
|
+
@delayed_delta = ThinkingSphinx::Deltas::DelayedDelta.new(
|
14
|
+
stub('instance'), {}
|
15
|
+
)
|
16
|
+
@delayed_delta.stub!(:toggled => true)
|
17
|
+
|
18
|
+
@model = stub('foo')
|
19
|
+
@model.stub!(:name => 'foo')
|
20
|
+
@model.stub!(:source_of_sphinx_index => @model)
|
21
|
+
@model.stub!(:core_index_names => ['foo_core'])
|
22
|
+
@model.stub!(:delta_index_names => ['foo_delta'])
|
23
|
+
|
24
|
+
@instance = stub('instance')
|
25
|
+
@instance.stub!(:sphinx_document_id => 42)
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'updates disabled' do
|
29
|
+
before :each do
|
30
|
+
ThinkingSphinx.updates_enabled = false
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should not enqueue a delta job" do
|
34
|
+
ThinkingSphinx::Deltas::Job.should_not_receive(:enqueue)
|
35
|
+
|
36
|
+
@delayed_delta.index(@model)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should not enqueue a flag as deleted job" do
|
40
|
+
Delayed::Job.should_not_receive(:enqueue)
|
41
|
+
|
42
|
+
@delayed_delta.index(@model)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'deltas disabled' do
|
47
|
+
before :each do
|
48
|
+
ThinkingSphinx.deltas_enabled = false
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should not enqueue a delta job" do
|
52
|
+
ThinkingSphinx::Deltas::Job.should_not_receive(:enqueue)
|
53
|
+
|
54
|
+
@delayed_delta.index(@model)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should not enqueue a flag as deleted job" do
|
58
|
+
Delayed::Job.should_not_receive(:enqueue)
|
59
|
+
|
60
|
+
@delayed_delta.index(@model)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
context "instance isn't toggled" do
|
65
|
+
before :each do
|
66
|
+
@delayed_delta.stub!(:toggled => false)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should not enqueue a delta job" do
|
70
|
+
ThinkingSphinx::Deltas::Job.should_not_receive(:enqueue)
|
71
|
+
|
72
|
+
@delayed_delta.index(@model, @instance)
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should not enqueue a flag as deleted job" do
|
76
|
+
Delayed::Job.should_not_receive(:enqueue)
|
77
|
+
|
78
|
+
@delayed_delta.index(@model, @instance)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should enqueue a delta job for the appropriate indexes" do
|
83
|
+
ThinkingSphinx::Deltas::Job.should_receive(:enqueue) do |job, priority|
|
84
|
+
job.indexes.should == ['foo_delta']
|
85
|
+
end
|
86
|
+
|
87
|
+
@delayed_delta.index(@model)
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should use the defined priority for the delta job" do
|
91
|
+
ThinkingSphinx::Deltas::Job.should_receive(:enqueue) do |job, priority|
|
92
|
+
priority.should == 2
|
93
|
+
end
|
94
|
+
|
95
|
+
@delayed_delta.index(@model)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should enqueue a flag-as-deleted job for the appropriate indexes" do
|
99
|
+
Delayed::Job.should_receive(:enqueue) do |job, priority|
|
100
|
+
job.indexes.should == ['foo_core']
|
101
|
+
end
|
102
|
+
|
103
|
+
@delayed_delta.index(@model, @instance)
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should enqueue a flag-as-deleted job for the appropriate id" do
|
107
|
+
Delayed::Job.should_receive(:enqueue) do |job, priority|
|
108
|
+
job.document_id.should == 42
|
109
|
+
end
|
110
|
+
|
111
|
+
@delayed_delta.index(@model, @instance)
|
112
|
+
end
|
113
|
+
|
114
|
+
it "should use the defined priority for the flag-as-deleted job" do
|
115
|
+
Delayed::Job.should_receive(:enqueue) do |job, priority|
|
116
|
+
priority.should == 2
|
117
|
+
end
|
118
|
+
|
119
|
+
@delayed_delta.index(@model, @instance)
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should not enqueue a flag-as-deleted job if no instance is provided" do
|
123
|
+
Delayed::Job.should_not_receive(:enqueue)
|
124
|
+
|
125
|
+
@delayed_delta.index(@model)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
metadata
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: namxam-ts-delayed-delta
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 1
|
7
|
+
- 0
|
8
|
+
- 3
|
9
|
+
version: 1.0.3
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Pat Allan
|
13
|
+
- Maximilian Schulz
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-02-26 00:00:00 +01:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: thinking-sphinx
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 1
|
30
|
+
- 3
|
31
|
+
- 6
|
32
|
+
version: 1.3.6
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: delayed_job
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
segments:
|
43
|
+
- 1
|
44
|
+
- 8
|
45
|
+
- 4
|
46
|
+
version: 1.8.4
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: rspec
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
segments:
|
57
|
+
- 1
|
58
|
+
- 2
|
59
|
+
- 9
|
60
|
+
version: 1.2.9
|
61
|
+
type: :development
|
62
|
+
version_requirements: *id003
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: yard
|
65
|
+
prerelease: false
|
66
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
segments:
|
71
|
+
- 0
|
72
|
+
version: "0"
|
73
|
+
type: :development
|
74
|
+
version_requirements: *id004
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: cucumber
|
77
|
+
prerelease: false
|
78
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
segments:
|
83
|
+
- 0
|
84
|
+
version: "0"
|
85
|
+
type: :development
|
86
|
+
version_requirements: *id005
|
87
|
+
description: Manage delta indexes via Delayed Job for Thinking Sphinx (including fix for bundler)
|
88
|
+
email: max@jungeelite.de
|
89
|
+
executables: []
|
90
|
+
|
91
|
+
extensions: []
|
92
|
+
|
93
|
+
extra_rdoc_files:
|
94
|
+
- LICENSE
|
95
|
+
- README.textile
|
96
|
+
files:
|
97
|
+
- LICENSE
|
98
|
+
- README.textile
|
99
|
+
- lib/thinking_sphinx/deltas/delayed_delta.rb
|
100
|
+
- lib/thinking_sphinx/deltas/delayed_delta/delta_job.rb
|
101
|
+
- lib/thinking_sphinx/deltas/delayed_delta/flag_as_deleted_job.rb
|
102
|
+
- lib/thinking_sphinx/deltas/delayed_delta/job.rb
|
103
|
+
- lib/thinking_sphinx/deltas/delayed_delta/tasks.rb
|
104
|
+
has_rdoc: true
|
105
|
+
homepage: http://github.com/namxam/ts-delayed-delta
|
106
|
+
licenses: []
|
107
|
+
|
108
|
+
post_install_message:
|
109
|
+
rdoc_options:
|
110
|
+
- --charset=UTF-8
|
111
|
+
require_paths:
|
112
|
+
- lib
|
113
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
segments:
|
118
|
+
- 0
|
119
|
+
version: "0"
|
120
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
segments:
|
125
|
+
- 0
|
126
|
+
version: "0"
|
127
|
+
requirements: []
|
128
|
+
|
129
|
+
rubyforge_project:
|
130
|
+
rubygems_version: 1.3.6
|
131
|
+
signing_key:
|
132
|
+
specification_version: 3
|
133
|
+
summary: Thinking Sphinx - Delayed Deltas
|
134
|
+
test_files:
|
135
|
+
- features/delayed_deltas.feature
|
136
|
+
- features/step_definitions/common_steps.rb
|
137
|
+
- features/step_definitions/delayed_delta_steps.rb
|
138
|
+
- features/support/database.example.yml
|
139
|
+
- features/support/db/fixtures/delayed_betas.rb
|
140
|
+
- features/support/db/migrations/create_delayed_betas.rb
|
141
|
+
- features/support/env.rb
|
142
|
+
- features/support/models/delayed_beta.rb
|
143
|
+
- spec/spec.opts
|
144
|
+
- spec/spec_helper.rb
|
145
|
+
- spec/thinking_sphinx/deltas/delayed_delta/delta_job_spec.rb
|
146
|
+
- spec/thinking_sphinx/deltas/delayed_delta/flag_as_deleted_job_spec.rb
|
147
|
+
- spec/thinking_sphinx/deltas/delayed_delta/job_spec.rb
|
148
|
+
- spec/thinking_sphinx/deltas/delayed_delta_spec.rb
|