ts-resque-delta 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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.
@@ -0,0 +1,57 @@
1
+ Delayed Deltas for Thinking Sphinx (with Resque)
2
+ ================================================
3
+
4
+ **This code is HEAVILY borrowed from [ts-delayed-delta](http://github.com/freelancing-god/ts-delayed-delta).**
5
+
6
+ Installation
7
+ ------------
8
+
9
+ You'll need Thinking Sphinx 1.3.0 or later, and Resque as well. The latter is flagged as a dependency.
10
+
11
+ gem install ts-resque-delta
12
+
13
+ In your `Gemfile` file, with the rest of your gem dependencies:
14
+
15
+ gem 'ts-resque-delta', '0.0.1', :require => 'thinking_sphinx/deltas/resque_delta'
16
+
17
+ And add the following line to the bottom of your `Rakefile`:
18
+
19
+ require 'thinking_sphinx/deltas/resque_delta/tasks'
20
+
21
+ For the indexes you want to use this delta approach, make sure you set that up in their `define_index` blocks.
22
+
23
+ define_index do
24
+ # ...
25
+ set_property :delta => ThinkingSphinx::Deltas::ResqueDelta
26
+ end
27
+
28
+ 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.
29
+
30
+ def self.up
31
+ add_column :articles, :delta, :boolean, :default => true, :null => false
32
+ end
33
+
34
+ Usage
35
+ -----
36
+
37
+ Once you've got it all set up, all you need to do is make sure that the Resque worker is running. You can do this either by running Resque's workers and specifying the `:ts_delta` queue, or Thinking Sphinx's custom rake task:
38
+
39
+ rake thinking_sphinx:resque_delta
40
+
41
+ There's also a short name for the same task, to save your fingers some effort:
42
+
43
+ rake ts:rd
44
+
45
+ Original Contributors (for ts-delayed-delta)
46
+ --------------------------------------------
47
+
48
+ * [Pat Allan](http://github.com/freelancing-god)
49
+ * [Ryan Schlesinger](http://github.com/ryansch) (Allowing installs as a plugin)
50
+ * [Maximilian Schulz](http://max.jungeelite.de) (Ensuring compatibility with Bundler)
51
+ * [Edgars Beigarts](http://github.com/ebeigarts) (Adding intelligent description for tasks)
52
+ * [Alexander Simonov](http://simonov.me/) (Explicit table definition)
53
+
54
+ Copyright
55
+ ---------
56
+
57
+ Copyright (c) 2010 Aaron Gibralter, and released under an MIT Licence.
@@ -0,0 +1,6 @@
1
+ require 'rubygems'
2
+
3
+ require 'tasks/distribution'
4
+ require 'tasks/testing'
5
+
6
+ task :default => :spec
@@ -0,0 +1,13 @@
1
+ daemonize yes
2
+ pidfile tmp/redis-cucumber.pid
3
+ port 6398
4
+ timeout 300
5
+ save 900 1
6
+ save 300 10
7
+ save 60 10000
8
+ dbfilename tmp/redis-cucumber-dump.rdb
9
+ dir .
10
+ loglevel debug
11
+ logfile stdout
12
+ databases 16
13
+ glueoutputbuf yes
@@ -0,0 +1,62 @@
1
+ Feature: Resque Delta Indexing
2
+ In order to have delta indexing on frequently-updated sites
3
+ Developers
4
+ Should be able to use Resque to handle delta indexes to lower system load
5
+
6
+ Background:
7
+ Given Sphinx is running
8
+ And I am searching on delayed betas
9
+ And I have data and it has been indexed
10
+
11
+ Scenario: Delta Index should not fire automatically
12
+ When I search for one
13
+ Then I should get 1 result
14
+
15
+ When I change the name of delayed beta one to eleven
16
+ And I wait for Sphinx to catch up
17
+ And I search for one
18
+ Then I should get 1 result
19
+
20
+ When I search for eleven
21
+ Then I should get 0 results
22
+
23
+ Scenario: Delta Index should fire when jobs are run
24
+ When I search for one
25
+ Then I should get 1 result
26
+
27
+ When I change the name of delayed beta two to twelve
28
+ And I wait for Sphinx to catch up
29
+ And I search for twelve
30
+ Then I should get 0 results
31
+
32
+ When I run the delayed jobs
33
+ And I wait for Sphinx to catch up
34
+ And I search for twelve
35
+ Then I should get 1 result
36
+
37
+ When I search for two
38
+ Then I should get 0 results
39
+
40
+ Scenario: ensuring that duplicate jobs are deleted
41
+ When I change the name of delayed beta two to fifty
42
+ And I change the name of delayed beta five to twelve
43
+ And I change the name of delayed beta one to fifteen
44
+ And I change the name of delayed beta six to twenty
45
+ And I run one delayed job
46
+ Then there should be no more DeltaJobs on the Resque queue
47
+
48
+ When I run the delayed jobs
49
+ And I wait for Sphinx to catch up
50
+ And I search for fifty
51
+ Then I should get 1 result
52
+
53
+ When I search for two
54
+ Then I should get 0 results
55
+
56
+ Scenario: canceling jobs
57
+ When I change the name of delayed beta two to fifty
58
+ And I cancel the jobs
59
+ And I run the delayed jobs
60
+ And I wait for Sphinx to catch up
61
+ And I search for fifty
62
+ Then I should get 0 results
@@ -0,0 +1,63 @@
1
+ Before do
2
+ $queries_executed = []
3
+ ThinkingSphinx::Deltas::ResqueDelta.cancel_thinking_sphinx_jobs
4
+ @model = nil
5
+ @method = :search
6
+ @query = ""
7
+ @conditions = {}
8
+ @with = {}
9
+ @without = {}
10
+ @with_all = {}
11
+ @options = {}
12
+ @results = nil
13
+ end
14
+
15
+ Given "Sphinx is running" do
16
+ ThinkingSphinx::Configuration.instance.controller.should be_running
17
+ end
18
+
19
+ Given /^I am searching on (.+)$/ do |model|
20
+ @model = model.gsub(/\s/, '_').singularize.camelize.constantize
21
+ end
22
+
23
+ Given "I have data and it has been indexed" do
24
+ DelayedBeta.create(:name => "one")
25
+ DelayedBeta.create(:name => "two")
26
+ DelayedBeta.create(:name => "three")
27
+ DelayedBeta.create(:name => "four")
28
+ DelayedBeta.create(:name => "five")
29
+ DelayedBeta.create(:name => "six")
30
+ DelayedBeta.create(:name => "seven")
31
+ DelayedBeta.create(:name => "eight")
32
+ DelayedBeta.create(:name => "nine")
33
+ DelayedBeta.create(:name => "ten")
34
+ ThinkingSphinx::Deltas::ResqueDelta.cancel_thinking_sphinx_jobs
35
+ ThinkingSphinx::Configuration.instance.controller.index
36
+ sleep(1.5)
37
+ end
38
+
39
+ When "I wait for Sphinx to catch up" do
40
+ sleep(0.5)
41
+ end
42
+
43
+ When /^I search for (\w+)$/ do |query|
44
+ @results = nil
45
+ @query = query
46
+ end
47
+
48
+ Then /^I should get (\d+) results?$/ do |count|
49
+ results.length.should == count.to_i
50
+ end
51
+
52
+ def results
53
+ @results ||= (@model || ThinkingSphinx).send(
54
+ @method,
55
+ @query,
56
+ @options.merge(
57
+ :conditions => @conditions,
58
+ :with => @with,
59
+ :without => @without,
60
+ :with_all => @with_all
61
+ )
62
+ )
63
+ end
@@ -0,0 +1,33 @@
1
+ When /^I run the delayed jobs$/ do
2
+ unless @resque_worker
3
+ @resque_worker = Resque::Worker.new("ts_delta")
4
+ @resque_worker.register_worker
5
+ end
6
+ while job = @resque_worker.reserve
7
+ @resque_worker.perform(job)
8
+ end
9
+ end
10
+
11
+ When /^I run one delayed job$/ do
12
+ unless @resque_worker
13
+ @resque_worker = Resque::Worker.new("ts_delta")
14
+ @resque_worker.register_worker
15
+ end
16
+ job = @resque_worker.reserve
17
+ @resque_worker.perform(job)
18
+ end
19
+
20
+ When /^I cancel the jobs$/ do
21
+ ThinkingSphinx::Deltas::ResqueDelta.cancel_thinking_sphinx_jobs
22
+ end
23
+
24
+ When /^I change the name of delayed beta (\w+) to (\w+)$/ do |current, replacement|
25
+ DelayedBeta.find_by_name(current).update_attributes(:name => replacement)
26
+ end
27
+
28
+ Then /^there should be no more DeltaJobs on the Resque queue$/ do
29
+ job_classes = Resque.redis.lrange("queue:ts_delta", 0, -1).collect do |j|
30
+ Resque.decode(j)["class"]
31
+ end
32
+ job_classes.should_not include("ThinkingSphinx::Deltas::ResqueDelta::DeltaJob")
33
+ end
@@ -0,0 +1,35 @@
1
+ require 'rubygems'
2
+ require 'cucumber'
3
+ require 'spec/expectations'
4
+ require 'fileutils'
5
+ require 'active_record'
6
+
7
+ PROJECT_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..', '..'))
8
+
9
+ $:.unshift(File.join(PROJECT_ROOT, 'lib'))
10
+ $:.unshift(File.dirname(__FILE__))
11
+
12
+ require 'cucumber/thinking_sphinx/internal_world'
13
+
14
+ Time.zone_default = Time.__send__(:get_zone, 'Melbourne')
15
+ ActiveRecord::Base.time_zone_aware_attributes = true
16
+ ActiveRecord::Base.default_timezone = :utc
17
+
18
+ world = Cucumber::ThinkingSphinx::InternalWorld.new
19
+ world.configure_database
20
+
21
+ require 'thinking_sphinx'
22
+ require 'thinking_sphinx/deltas/resque_delta'
23
+
24
+ world.setup
25
+
26
+ require 'redis_test_setup'
27
+ RedisTestSetup.start_redis!(PROJECT_ROOT, :cucumber)
28
+ Resque.redis = '127.0.0.1:6398'
29
+ Before do
30
+ Resque.redis.flushall
31
+ end
32
+
33
+ require 'database_cleaner'
34
+ require 'database_cleaner/cucumber'
35
+ DatabaseCleaner.strategy = :truncation
@@ -0,0 +1,23 @@
1
+ module RedisTestSetup
2
+
3
+ def self.start_redis!(rails_root, env)
4
+ dir_temp = File.expand_path(File.join(rails_root, 'tmp'))
5
+ dir_conf = File.expand_path(File.join(rails_root, 'config'))
6
+ cwd = Dir.getwd
7
+ Dir.chdir(rails_root)
8
+ self.cleanup(dir_temp, env)
9
+ raise "unable to launch redis-server" unless system("redis-server #{dir_conf}/redis-#{env}.conf")
10
+ Dir.chdir(cwd)
11
+ Kernel.at_exit do
12
+ if (pid = `cat #{dir_temp}/redis-#{env}.pid`.strip) =~ /^\d+$/
13
+ self.cleanup(dir_temp, env)
14
+ Process.kill("KILL", pid.to_i)
15
+ end
16
+ end
17
+ end
18
+
19
+ def self.cleanup(dir_temp, env)
20
+ `rm -f #{dir_temp}/redis-#{env}-dump.rdb`
21
+ `rm -f #{dir_temp}/redis-#{env}.pid`
22
+ end
23
+ end
@@ -0,0 +1,3 @@
1
+ username: root
2
+ host: localhost
3
+ password:
@@ -0,0 +1,5 @@
1
+ username: root
2
+ password: BdUKNL5Cimo9yAVzITEv
3
+ host: localhost
4
+ pool: 1
5
+ min_messages: warning
@@ -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,6 @@
1
+ class DelayedBeta < ActiveRecord::Base
2
+ define_index do
3
+ indexes :name, :sortable => true
4
+ set_property :delta => ThinkingSphinx::Deltas::ResqueDelta
5
+ end
6
+ end
@@ -0,0 +1,74 @@
1
+ require 'resque'
2
+ require 'thinking_sphinx'
3
+
4
+ # Delayed Deltas for Thinking Sphinx, using Resque.
5
+ #
6
+ # This documentation is aimed at those reading the code. If you're looking for
7
+ # a guide to Thinking Sphinx and/or deltas, I recommend you start with the
8
+ # Thinking Sphinx site instead - or the README for this library at the very
9
+ # least.
10
+ #
11
+ # @author Patrick Allan
12
+ # @see http://ts.freelancing-gods.com Thinking Sphinx
13
+ #
14
+ class ThinkingSphinx::Deltas::ResqueDelta < ThinkingSphinx::Deltas::DefaultDelta
15
+
16
+ # LTRIM + LPOP deletes all items from the Resque queue without loading it
17
+ # into client memory (unlike Resque.dequeue).
18
+ def self.cancel_thinking_sphinx_jobs
19
+ [
20
+ ThinkingSphinx::Deltas::ResqueDelta::DeltaJob,
21
+ ThinkingSphinx::Deltas::ResqueDelta::FlagAsDeletedJob
22
+ ].collect { |c| c.instance_variable_get(:@queue) }.uniq.each do |q|
23
+ Resque.redis.ltrim("queue:#{q}", 0, 0)
24
+ Resque.redis.lpop("queue:#{q}")
25
+ end
26
+ end
27
+
28
+ # Adds a job to the queue for processing the given model's delta index. A job
29
+ # for hiding the instance in the core index is also created, if an instance is
30
+ # provided.
31
+ #
32
+ # Neither job will be queued if updates or deltas are disabled, or if the
33
+ # instance (when given) is not toggled to be in the delta index. The first two
34
+ # options are controlled via ThinkingSphinx.updates_enabled? and
35
+ # ThinkingSphinx.deltas_enabled?.
36
+ #
37
+ # @param [Class] model the ActiveRecord model to index.
38
+ # @param [ActiveRecord::Base] instance the instance of the given model that
39
+ # has changed. Optional.
40
+ # @return [Boolean] true
41
+ #
42
+ def index(model, instance = nil)
43
+ return true if skip?(instance)
44
+ Resque.enqueue(
45
+ ThinkingSphinx::Deltas::ResqueDelta::DeltaJob,
46
+ model.delta_index_names
47
+ )
48
+ if instance
49
+ Resque.enqueue(
50
+ ThinkingSphinx::Deltas::ResqueDelta::FlagAsDeletedJob,
51
+ model.core_index_names,
52
+ instance.sphinx_document_id
53
+ )
54
+ end
55
+ true
56
+ end
57
+
58
+ private
59
+
60
+ # Checks whether jobs should be enqueued. Only true if updates and deltas are
61
+ # enabled, and the instance (if there is one) is toggled.
62
+ #
63
+ # @param [ActiveRecord::Base, NilClass] instance
64
+ # @return [Boolean]
65
+ #
66
+ def skip?(instance)
67
+ !ThinkingSphinx.updates_enabled? ||
68
+ !ThinkingSphinx.deltas_enabled? ||
69
+ (instance && !toggled(instance))
70
+ end
71
+ end
72
+
73
+ require 'thinking_sphinx/deltas/resque_delta/delta_job'
74
+ require 'thinking_sphinx/deltas/resque_delta/flag_as_deleted_job'
@@ -0,0 +1,54 @@
1
+ require 'resque-lock-timeout'
2
+
3
+ # A simple job class that processes a given index.
4
+ #
5
+ class ThinkingSphinx::Deltas::ResqueDelta::DeltaJob
6
+
7
+ extend Resque::Plugins::LockTimeout
8
+ @queue = :ts_delta
9
+ @lock_timeout = 240
10
+
11
+ # Runs Sphinx's indexer tool to process the index. Currently assumes Sphinx
12
+ # is running.
13
+ #
14
+ # @param [String] index the name of the Sphinx index
15
+ #
16
+ def self.perform(indexes)
17
+ config = ThinkingSphinx::Configuration.instance
18
+ output = `#{config.bin_path}#{config.indexer_binary_name} --config #{config.config_file} --rotate #{indexes.join(' ')}`
19
+ puts output unless ThinkingSphinx.suppress_delta_output?
20
+ end
21
+
22
+ # Try again later if lock is in use.
23
+ def self.lock_failed(*args)
24
+ Resque.enqueue(self, *args)
25
+ end
26
+
27
+ # Run only one DeltaJob at a time regardless of indexes.
28
+ def self.identifier(*args)
29
+ nil
30
+ end
31
+
32
+ # This allows us to have a concurrency safe version of ts-delayed-delta's
33
+ # duplicates_exist:
34
+ #
35
+ # http://github.com/freelancing-god/ts-delayed-delta/blob/master/lib/thinkin
36
+ # g_sphinx/deltas/delayed_delta/job.rb#L47
37
+ #
38
+ # The name of this method ensures that it runs within around_perform_lock.
39
+ #
40
+ # We've leveraged resque-lock-timeout to ensure that only one DeltaJob is
41
+ # running at a time. Now, this around filter essentially ensures that only
42
+ # one DeltaJob of each index type can sit at the queue at once. If the queue
43
+ # has more than one, lrem will clear the rest off.
44
+ #
45
+ def self.around_perform_lock1(*args)
46
+ # Remove all other instances of this job (with the same args) from the
47
+ # queue. Uses LREM (http://code.google.com/p/redis/wiki/LremCommand) which
48
+ # takes the form: "LREM key count value" and if count == 0 removes all
49
+ # instances of value from the list.
50
+ redis_job_value = Resque.encode(:class => self.to_s, :args => args)
51
+ Resque.redis.lrem("queue:#{@queue}", 0, redis_job_value)
52
+ yield
53
+ end
54
+ end
@@ -0,0 +1,30 @@
1
+ # A simple job for flagging a specified Sphinx document in a given index as
2
+ # 'deleted'.
3
+ #
4
+ class ThinkingSphinx::Deltas::ResqueDelta::FlagAsDeletedJob
5
+
6
+ @queue = :ts_delta
7
+
8
+ # Takes an index name and document id. Please note that the document id is
9
+ # Sphinx's unique identifier, and will almost certainly not be the model
10
+ # instance's primary key value. Updates the sphinx_deleted attribute for the
11
+ # given document, setting the value to 1 (true). This is not a special
12
+ # attribute in Sphinx, but is used by Thinking Sphinx to ignore deleted
13
+ # values between full re-indexing. It's particularly useful in this
14
+ # situation to avoid old values in the core index and just use the new
15
+ # values in the delta index as a reference point.
16
+ #
17
+ # @param [Array] indexes An array of index names
18
+ # @param [Integer] document_id The document id
19
+ #
20
+ # @return [Boolean] true
21
+ #
22
+ def self.perform(indexes, document_id)
23
+ config = ThinkingSphinx::Configuration.instance
24
+ indexes.each do |index|
25
+ if ThinkingSphinx.sphinx_running? && ThinkingSphinx.search_for_id(document_id, index)
26
+ config.client.update(index, ['sphinx_deleted'], {document_id => [1]})
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,22 @@
1
+ namespace :thinking_sphinx do
2
+ task :index do
3
+ ThinkingSphinx::Deltas::ResqueDelta.cancel_thinking_sphinx_jobs
4
+ end
5
+
6
+ desc "Process stored delta index requests"
7
+ task :resque_delta => :app_env do
8
+ raise "TODO... for now, please just run the workers on your own and make sure to work the :ts_delta queue."
9
+ # require 'delayed/worker'
10
+ # require 'thinking_sphinx/deltas/resque_delta'
11
+ #
12
+ # Delayed::Worker.new(
13
+ # :min_priority => ENV['MIN_PRIORITY'],
14
+ # :max_priority => ENV['MAX_PRIORITY']
15
+ # ).start
16
+ end
17
+ end
18
+
19
+ namespace :ts do
20
+ desc "Process stored delta index requests"
21
+ task :rd => "thinking_sphinx:resque_delta"
22
+ end
@@ -0,0 +1 @@
1
+ --color
@@ -0,0 +1,8 @@
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/resque_delta'
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe ThinkingSphinx::Deltas::ResqueDelta::DeltaJob do
4
+ describe '.perform' do
5
+ before :each do
6
+ ThinkingSphinx.suppress_delta_output = false
7
+ ThinkingSphinx::Deltas::ResqueDelta::DeltaJob.stub(:` => true)
8
+ ThinkingSphinx::Deltas::ResqueDelta::DeltaJob.stub(:puts => nil)
9
+ end
10
+
11
+ it "should output the delta indexing by default" do
12
+ ThinkingSphinx::Deltas::ResqueDelta::DeltaJob.should_receive(:puts)
13
+ ThinkingSphinx::Deltas::ResqueDelta::DeltaJob.perform(['foo_core'])
14
+ end
15
+
16
+ it "should not output the delta indexing if requested" do
17
+ ThinkingSphinx.suppress_delta_output = true
18
+ ThinkingSphinx::Deltas::ResqueDelta::DeltaJob.should_not_receive(:puts)
19
+ ThinkingSphinx::Deltas::ResqueDelta::DeltaJob.perform(['foo_core'])
20
+ end
21
+
22
+ it "should process just the requested indexes" do
23
+ ThinkingSphinx::Deltas::ResqueDelta::DeltaJob.should_receive(:`) do |command|
24
+ command.should match(/foo_core/)
25
+ command.should_not match(/--all/)
26
+ end
27
+ ThinkingSphinx::Deltas::ResqueDelta::DeltaJob.perform(['foo_core'])
28
+ end
29
+
30
+ context 'multiple indexes' do
31
+ it "should process all requested indexes" do
32
+ ThinkingSphinx::Deltas::ResqueDelta::DeltaJob.should_receive(:`) do |command|
33
+ command.should match(/foo_core bar_core/)
34
+ end
35
+ ThinkingSphinx::Deltas::ResqueDelta::DeltaJob.perform(['foo_core', 'bar_core'])
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,66 @@
1
+ require 'spec_helper'
2
+
3
+ describe ThinkingSphinx::Deltas::ResqueDelta::FlagAsDeletedJob do
4
+ describe '.perform' do
5
+ before :each do
6
+ ThinkingSphinx.updates_enabled = true
7
+ @client = stub('client', :update => true)
8
+ ThinkingSphinx::Configuration.instance.stub!(:client => @client)
9
+ ThinkingSphinx.stub!(:search_for_id => true)
10
+ ThinkingSphinx.stub!(:sphinx_running? => true)
11
+ end
12
+
13
+ it "should not update if Sphinx isn't running" do
14
+ ThinkingSphinx.stub!(:sphinx_running? => false)
15
+ @client.should_not_receive(:update)
16
+ ThinkingSphinx::Deltas::ResqueDelta::FlagAsDeletedJob.perform(['foo_core'], 12)
17
+ end
18
+
19
+ it "should not update if the document isn't in the index" do
20
+ ThinkingSphinx.stub!(:search_for_id => false)
21
+ @client.should_not_receive(:update)
22
+ ThinkingSphinx::Deltas::ResqueDelta::FlagAsDeletedJob.perform(['foo_core'], 12)
23
+ end
24
+
25
+ it "should update the specified index" do
26
+ @client.should_receive(:update) do |index, attributes, values|
27
+ index.should == 'foo_core'
28
+ end
29
+ ThinkingSphinx::Deltas::ResqueDelta::FlagAsDeletedJob.perform(['foo_core'], 12)
30
+ end
31
+
32
+ it "should update all specified indexes" do
33
+ @client.should_receive(:update).with('foo_core', anything, anything)
34
+ @client.should_receive(:update).with('bar_core', anything, anything)
35
+ ThinkingSphinx::Deltas::ResqueDelta::FlagAsDeletedJob.perform(['foo_core', 'bar_core'], 12)
36
+ end
37
+
38
+ it "should update the sphinx_deleted attribute" do
39
+ @client.should_receive(:update) do |index, attributes, values|
40
+ attributes.should == ['sphinx_deleted']
41
+ end
42
+ ThinkingSphinx::Deltas::ResqueDelta::FlagAsDeletedJob.perform(['foo_core'], 12)
43
+ end
44
+
45
+ it "should set sphinx_deleted for the given document to true" do
46
+ @client.should_receive(:update) do |index, attributes, values|
47
+ values[12].should == [1]
48
+ end
49
+ ThinkingSphinx::Deltas::ResqueDelta::FlagAsDeletedJob.perform(['foo_core'], 12)
50
+ end
51
+
52
+ it "should check for the existence of the document in the specified index" do
53
+ ThinkingSphinx.should_receive(:search_for_id) do |id, index|
54
+ index.should == 'foo_core'
55
+ end
56
+ ThinkingSphinx::Deltas::ResqueDelta::FlagAsDeletedJob.perform(['foo_core'], 12)
57
+ end
58
+
59
+ it "should check for the existence of the given document id" do
60
+ ThinkingSphinx.should_receive(:search_for_id) do |id, index|
61
+ id.should == 12
62
+ end
63
+ ThinkingSphinx::Deltas::ResqueDelta::FlagAsDeletedJob.perform(['foo_core'], 12)
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,93 @@
1
+ require 'spec_helper'
2
+
3
+ describe ThinkingSphinx::Deltas::ResqueDelta do
4
+ describe '#index' do
5
+ before :each do
6
+ ThinkingSphinx.updates_enabled = true
7
+ ThinkingSphinx.deltas_enabled = true
8
+
9
+ Resque.stub!(:enqueue => true)
10
+
11
+ @delayed_delta = ThinkingSphinx::Deltas::ResqueDelta.new(
12
+ stub('instance'), {}
13
+ )
14
+ @delayed_delta.stub!(:toggled => true)
15
+
16
+ @model = stub('foo')
17
+ @model.stub!(:name => 'foo')
18
+ @model.stub!(:source_of_sphinx_index => @model)
19
+ @model.stub!(:core_index_names => ['foo_core'])
20
+ @model.stub!(:delta_index_names => ['foo_delta'])
21
+
22
+ @instance = stub('instance')
23
+ @instance.stub!(:sphinx_document_id => 42)
24
+ end
25
+
26
+ context 'updates disabled' do
27
+ before :each do
28
+ ThinkingSphinx.updates_enabled = false
29
+ end
30
+
31
+ it "should not enqueue a delta job" do
32
+ Resque.should_not_receive(:enqueue)
33
+ @delayed_delta.index(@model)
34
+ end
35
+
36
+ it "should not enqueue a flag as deleted job" do
37
+ Resque.should_not_receive(:enqueue)
38
+ @delayed_delta.index(@model)
39
+ end
40
+ end
41
+
42
+ context 'deltas disabled' do
43
+ before :each do
44
+ ThinkingSphinx.deltas_enabled = false
45
+ end
46
+
47
+ it "should not enqueue a delta job" do
48
+ Resque.should_not_receive(:enqueue)
49
+ @delayed_delta.index(@model)
50
+ end
51
+
52
+ it "should not enqueue a flag as deleted job" do
53
+ Resque.should_not_receive(:enqueue)
54
+ @delayed_delta.index(@model)
55
+ end
56
+ end
57
+
58
+ context "instance isn't toggled" do
59
+ before :each do
60
+ @delayed_delta.stub!(:toggled => false)
61
+ end
62
+
63
+ it "should not enqueue a delta job" do
64
+ Resque.should_not_receive(:enqueue)
65
+ @delayed_delta.index(@model, @instance)
66
+ end
67
+
68
+ it "should not enqueue a flag as deleted job" do
69
+ Resque.should_not_receive(:enqueue)
70
+ @delayed_delta.index(@model, @instance)
71
+ end
72
+ end
73
+
74
+ it "should enqueue a delta job for the appropriate indexes" do
75
+ Resque.should_receive(:enqueue).with(ThinkingSphinx::Deltas::ResqueDelta::DeltaJob, ['foo_delta']).once
76
+ @delayed_delta.index(@model)
77
+ end
78
+
79
+ it "should enqueue a flag-as-deleted job for the appropriate indexes" do
80
+ # WTF RSpec: http://gist.github.com/447611
81
+ # Resque.should_receive(:enqueue).with(ThinkingSphinx::Deltas::ResqueDelta::FlagAsDeletedJob, ['foo_core'], an_instance_of(Numeric))
82
+ Resque.should_receive(:enqueue).twice
83
+ @delayed_delta.index(@model, @instance)
84
+ end
85
+
86
+ it "should enqueue a flag-as-deleted job for the appropriate id" do
87
+ # WTF RSpec: http://gist.github.com/447611
88
+ # Resque.should_receive(:enqueue).with(ThinkingSphinx::Deltas::ResqueDelta::FlagAsDeletedJob, an_instance_of(Array), 42)
89
+ Resque.should_receive(:enqueue).twice
90
+ @delayed_delta.index(@model, @instance)
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,29 @@
1
+ require "jeweler"
2
+ require "yard"
3
+
4
+ YARD::Rake::YardocTask.new
5
+
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "ts-resque-delta"
8
+ gem.summary = "Thinking Sphinx - Resque Deltas"
9
+ gem.description = "Manage delta indexes via Resque for Thinking Sphinx"
10
+ gem.email = "aaron.gibralter@gmail.com"
11
+ gem.homepage = "http://github.com/agibralter/ts-resque-delta"
12
+ gem.authors = ["Aaron Gibralter"]
13
+ gem.add_dependency("thinking-sphinx", ">= 1.3.6")
14
+ gem.add_dependency("resque", ">= 1.9.0")
15
+ gem.add_development_dependency("rspec", ">= 1.2.9")
16
+ gem.add_development_dependency("yard", ">= 0")
17
+ gem.add_development_dependency("cucumber", ">= 0")
18
+ gem.add_development_dependency("database_cleaner", ">= 0.5.2")
19
+ gem.files = FileList[
20
+ "lib/**/*.rb",
21
+ "LICENSE",
22
+ "README.markdown"
23
+ ]
24
+ gem.test_files = FileList[
25
+ ["Rakefile"] + %w(config features spec tasks).collect { |d| "#{d}/**/*" }
26
+ ]
27
+ end
28
+
29
+ Jeweler::GemcutterTasks.new
@@ -0,0 +1 @@
1
+ require File.join(File.dirname(__FILE__), '/../lib/thinking_sphinx/deltas/delayed_delta/tasks')
@@ -0,0 +1,20 @@
1
+ require 'spec/rake/spectask'
2
+ require 'cucumber/rake/task'
3
+
4
+ Spec::Rake::SpecTask.new(:spec) do |spec|
5
+ spec.libs << 'lib' << 'spec'
6
+ spec.spec_files = FileList['spec/**/*_spec.rb']
7
+ end
8
+
9
+ Spec::Rake::SpecTask.new(:rcov) do |spec|
10
+ spec.libs << 'lib' << 'spec'
11
+ spec.pattern = 'spec/**/*_spec.rb'
12
+ spec.rcov = true
13
+ end
14
+
15
+ Cucumber::Rake::Task.new do |task|
16
+ task.cucumber_opts = '--exclude features/thinking_sphinx'
17
+ end
18
+
19
+ task :spec => :check_dependencies
20
+ task :cucumber => :check_dependencies
metadata ADDED
@@ -0,0 +1,201 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ts-resque-delta
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Aaron Gibralter
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-06-23 00:00:00 -04: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
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 23
30
+ segments:
31
+ - 1
32
+ - 3
33
+ - 6
34
+ version: 1.3.6
35
+ type: :runtime
36
+ version_requirements: *id001
37
+ - !ruby/object:Gem::Dependency
38
+ name: resque
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ hash: 51
46
+ segments:
47
+ - 1
48
+ - 9
49
+ - 0
50
+ version: 1.9.0
51
+ type: :runtime
52
+ version_requirements: *id002
53
+ - !ruby/object:Gem::Dependency
54
+ name: rspec
55
+ prerelease: false
56
+ requirement: &id003 !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ hash: 13
62
+ segments:
63
+ - 1
64
+ - 2
65
+ - 9
66
+ version: 1.2.9
67
+ type: :development
68
+ version_requirements: *id003
69
+ - !ruby/object:Gem::Dependency
70
+ name: yard
71
+ prerelease: false
72
+ requirement: &id004 !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ hash: 3
78
+ segments:
79
+ - 0
80
+ version: "0"
81
+ type: :development
82
+ version_requirements: *id004
83
+ - !ruby/object:Gem::Dependency
84
+ name: cucumber
85
+ prerelease: false
86
+ requirement: &id005 !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ hash: 3
92
+ segments:
93
+ - 0
94
+ version: "0"
95
+ type: :development
96
+ version_requirements: *id005
97
+ - !ruby/object:Gem::Dependency
98
+ name: database_cleaner
99
+ prerelease: false
100
+ requirement: &id006 !ruby/object:Gem::Requirement
101
+ none: false
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ hash: 15
106
+ segments:
107
+ - 0
108
+ - 5
109
+ - 2
110
+ version: 0.5.2
111
+ type: :development
112
+ version_requirements: *id006
113
+ description: Manage delta indexes via Resque for Thinking Sphinx
114
+ email: aaron.gibralter@gmail.com
115
+ executables: []
116
+
117
+ extensions: []
118
+
119
+ extra_rdoc_files:
120
+ - LICENSE
121
+ - README.markdown
122
+ files:
123
+ - LICENSE
124
+ - README.markdown
125
+ - lib/thinking_sphinx/deltas/resque_delta.rb
126
+ - lib/thinking_sphinx/deltas/resque_delta/delta_job.rb
127
+ - lib/thinking_sphinx/deltas/resque_delta/flag_as_deleted_job.rb
128
+ - lib/thinking_sphinx/deltas/resque_delta/tasks.rb
129
+ - Rakefile
130
+ - config/redis-cucumber.conf
131
+ - features/resque_deltas.feature
132
+ - features/step_definitions/common_steps.rb
133
+ - features/step_definitions/resque_delta_steps.rb
134
+ - features/support/env.rb
135
+ - features/support/redis_test_setup.rb
136
+ - features/thinking_sphinx/database.example.yml
137
+ - features/thinking_sphinx/database.yml
138
+ - features/thinking_sphinx/db/migrations/create_delayed_betas.rb
139
+ - features/thinking_sphinx/models/delayed_beta.rb
140
+ - spec/spec.opts
141
+ - spec/spec_helper.rb
142
+ - spec/thinking_sphinx/deltas/resque_delta/delta_job_spec.rb
143
+ - spec/thinking_sphinx/deltas/resque_delta/flag_as_deleted_job_spec.rb
144
+ - spec/thinking_sphinx/deltas/resque_delta_spec.rb
145
+ - tasks/distribution.rb
146
+ - tasks/rails.rake
147
+ - tasks/testing.rb
148
+ has_rdoc: true
149
+ homepage: http://github.com/agibralter/ts-resque-delta
150
+ licenses: []
151
+
152
+ post_install_message:
153
+ rdoc_options:
154
+ - --charset=UTF-8
155
+ require_paths:
156
+ - lib
157
+ required_ruby_version: !ruby/object:Gem::Requirement
158
+ none: false
159
+ requirements:
160
+ - - ">="
161
+ - !ruby/object:Gem::Version
162
+ hash: 3
163
+ segments:
164
+ - 0
165
+ version: "0"
166
+ required_rubygems_version: !ruby/object:Gem::Requirement
167
+ none: false
168
+ requirements:
169
+ - - ">="
170
+ - !ruby/object:Gem::Version
171
+ hash: 3
172
+ segments:
173
+ - 0
174
+ version: "0"
175
+ requirements: []
176
+
177
+ rubyforge_project:
178
+ rubygems_version: 1.3.7
179
+ signing_key:
180
+ specification_version: 3
181
+ summary: Thinking Sphinx - Resque Deltas
182
+ test_files:
183
+ - Rakefile
184
+ - config/redis-cucumber.conf
185
+ - features/resque_deltas.feature
186
+ - features/step_definitions/common_steps.rb
187
+ - features/step_definitions/resque_delta_steps.rb
188
+ - features/support/env.rb
189
+ - features/support/redis_test_setup.rb
190
+ - features/thinking_sphinx/database.example.yml
191
+ - features/thinking_sphinx/database.yml
192
+ - features/thinking_sphinx/db/migrations/create_delayed_betas.rb
193
+ - features/thinking_sphinx/models/delayed_beta.rb
194
+ - spec/spec.opts
195
+ - spec/spec_helper.rb
196
+ - spec/thinking_sphinx/deltas/resque_delta/delta_job_spec.rb
197
+ - spec/thinking_sphinx/deltas/resque_delta/flag_as_deleted_job_spec.rb
198
+ - spec/thinking_sphinx/deltas/resque_delta_spec.rb
199
+ - tasks/distribution.rb
200
+ - tasks/rails.rake
201
+ - tasks/testing.rb