sunspot-queue 0.9.1 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,14 @@
1
+ # Sunspot Queue Changelog
2
+
3
+ ## 0.10.0
4
+ * Sidekiq support
5
+ * SessionProxy now takes a backend as a second required option
6
+ * Sunspot::Queue::Resque::Backend is the backend for Resque
7
+ * Sunspot::Queue::Sidekiq::Backend is the backend for Sidekiq
8
+
9
+ ## 0.9.1
10
+ * Jobs no longer auto commit the solr index. Commits should be done by another process or
11
+ Solr should be configured handle commits automatically (autoCommit config option).
12
+
13
+ ## 0.9.0
14
+ * Initial Release
data/README.md CHANGED
@@ -1,25 +1,88 @@
1
- # sunspot-queue
1
+ # sunspot-queue [![Build Status](https://secure.travis-ci.org/gaffneyc/sunspot-queue.png?branch=master)](http://travis-ci.org/gaffneyc/sunspot-queue)
2
2
 
3
3
  Background search indexing using existing worker systems.
4
4
 
5
5
  ## Install
6
6
 
7
- $ gem install sunspot-queue
7
+ ```console
8
+ $ gem install sunspot-queue
9
+ ```
8
10
 
9
- ## Usage with Rails (or without)
11
+ ## Usage with Rails and Resque
10
12
 
11
13
  In your Gemfile
12
14
 
13
- gem "sunspot-queue"
14
- gem "resque"
15
+ ```ruby
16
+ gem "sunspot-queue"
17
+ gem "resque"
18
+ ```
15
19
 
16
20
  In config/initializers/sunspot.rb
17
21
 
18
- Sunspot.session = Sunspot::Queue::SessionProxy.new(Sunspot.session)
22
+ ```ruby
23
+ require "sunspot/queue/resque"
24
+ backend = Sunspot::Queue::Resque::Backend.new
25
+ Sunspot.session = Sunspot::Queue::SessionProxy.new(Sunspot.session, backend)
26
+ ```
19
27
 
20
28
  Start Resque
21
29
 
22
- $ QUEUE=sunspot rake resque:work
30
+ ```console
31
+ $ QUEUE=sunspot rake resque:work
32
+ ```
33
+
34
+ ## Usage with Rails and Sidekiq
35
+
36
+ In your Gemfile
37
+
38
+ ```ruby
39
+ gem "sunspot-queue"
40
+ gem "sidekiq"
41
+ ```
42
+
43
+ In config/initializers/sunspot.rb
44
+
45
+ ```ruby
46
+ require "sunspot/queue/sidekiq"
47
+ backend = Sunspot::Queue::Sidekiq::Backend.new
48
+ Sunspot.session = Sunspot::Queue::SessionProxy.new(Sunspot.session, backend)
49
+ ```
50
+
51
+ Start Sidekiq
52
+
53
+ ```console
54
+ $ sidekiq -q sunspot
55
+ ```
56
+
57
+ ## Configuring Sunspot Queue
58
+
59
+ In config/initializers/sunspot.rb
60
+
61
+ ```ruby
62
+ Sunspot::Queue.configure do |config|
63
+ # Override default job classes
64
+ config.index_job = CustomIndexJob
65
+ config.removal_job = CustomRemovalJob
66
+ end
67
+ ```
68
+
69
+ ## Configuring Auto Commit
70
+
71
+ The sunspot-queue jobs update the Solr index but those changes don't appear in
72
+ search results until Solr commits those changes. Solr supports automatically
73
+ commiting changes based on either the number of changes and / or time between
74
+ commits.
75
+
76
+ Add (or uncomment) the following in solrconfig.xml
77
+
78
+ ```xml
79
+ <autoCommit>
80
+ <maxDocs>10000</maxDocs>
81
+ <maxTime>30000</maxTime>
82
+ </autoCommit>
83
+ ```
84
+
85
+ See [Solr's documentation](http://wiki.apache.org/solr/SolrConfigXml#Update_Handler_Section) for more information.
23
86
 
24
87
  ## Note on Patches/Pull Requests
25
88
 
@@ -32,9 +95,11 @@ Please don't make changes to the Rakefile, version, or history.
32
95
 
33
96
  ## Development
34
97
 
35
- $ gem install bundler (if you don't have it)
36
- $ bundle install
37
- $ guard
98
+ ```console
99
+ $ gem install bundler
100
+ $ bundle
101
+ $ guard
102
+ ```
38
103
 
39
104
  ## Copyright
40
105
 
@@ -2,10 +2,17 @@ module Sunspot
2
2
  module Queue
3
3
  class Error < StandardError; end
4
4
  class NotPersistedError < Error; end
5
+
6
+ def self.configure(&blk)
7
+ yield configuration
8
+ end
9
+
10
+ def self.configuration
11
+ @configuration ||= Sunspot::Queue::Configuration.new
12
+ end
5
13
  end
6
14
  end
7
15
 
8
16
  require "sunspot/queue/version"
17
+ require "sunspot/queue/configuration"
9
18
  require "sunspot/queue/session_proxy"
10
- require "sunspot/queue/index_job"
11
- require "sunspot/queue/removal_job"
@@ -0,0 +1,5 @@
1
+ module Sunspot::Queue
2
+ class Configuration
3
+ attr_accessor :index_job, :removal_job
4
+ end
5
+ end
@@ -16,5 +16,16 @@ module Sunspot::Queue
16
16
  ensure
17
17
  Sunspot.session = proxy if proxy
18
18
  end
19
+
20
+ def constantize(klass)
21
+ names = klass.to_s.split('::')
22
+ names.shift if names.empty? || names.first.empty?
23
+
24
+ constant = Object
25
+ names.each do |name|
26
+ constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
27
+ end
28
+ constant
29
+ end
19
30
  end
20
31
  end
@@ -0,0 +1,5 @@
1
+ module Sunspot::Queue
2
+ module Inline
3
+ require "sunspot/queue/inline/backend"
4
+ end
5
+ end
@@ -0,0 +1,20 @@
1
+ require "sunspot/queue/inline"
2
+ require "sunspot/queue/helpers"
3
+
4
+ module Sunspot::Queue::Inline
5
+ class Backend
6
+ include ::Sunspot::Queue::Helpers
7
+
8
+ def index(klass, id)
9
+ without_proxy do
10
+ constantize(klass).find(id).solr_index
11
+ end
12
+ end
13
+
14
+ def remove(klass, id)
15
+ without_proxy do
16
+ ::Sunspot.remove_by_id(klass, id)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,13 @@
1
+ require "sunspot/queue"
2
+
3
+ module Sunspot::Queue
4
+ module Resque
5
+ require "sunspot/queue/resque/backend"
6
+ require "sunspot/queue/resque/index_job"
7
+ require "sunspot/queue/resque/removal_job"
8
+ end
9
+ end
10
+
11
+ # Backwards compatability with 0.9.x. Will be removed by 1.0 / 0.11.
12
+ ::Sunspot::Queue::IndexJob = ::Sunspot::Queue::Resque::IndexJob
13
+ ::Sunspot::Queue::RemovalJob = ::Sunspot::Queue::Resque::RemovalJob
@@ -0,0 +1,35 @@
1
+ require "resque"
2
+ require "sunspot/queue/resque/index_job"
3
+ require "sunspot/queue/resque/removal_job"
4
+
5
+ module Sunspot::Queue::Resque
6
+ class Backend
7
+ attr_reader :configuration
8
+
9
+ def initialize(configuration = Sunspot::Queue.configuration)
10
+ @configuration = configuration
11
+ end
12
+
13
+ def enqueue(job, klass, id)
14
+ ::Resque.enqueue(job, klass, id)
15
+ end
16
+
17
+ def index(klass, id)
18
+ enqueue(index_job, klass, id)
19
+ end
20
+
21
+ def remove(klass, id)
22
+ enqueue(removal_job, klass, id)
23
+ end
24
+
25
+ private
26
+
27
+ def index_job
28
+ configuration.index_job || ::Sunspot::Queue::Resque::IndexJob
29
+ end
30
+
31
+ def removal_job
32
+ configuration.removal_job || ::Sunspot::Queue::Resque::RemovalJob
33
+ end
34
+ end
35
+ end
@@ -1,8 +1,8 @@
1
1
  require "sunspot/queue/helpers"
2
2
 
3
- module Sunspot::Queue
3
+ module Sunspot::Queue::Resque
4
4
  class IndexJob
5
- extend Helpers
5
+ extend ::Sunspot::Queue::Helpers
6
6
 
7
7
  def self.queue
8
8
  :sunspot
@@ -10,7 +10,7 @@ module Sunspot::Queue
10
10
 
11
11
  def self.perform(klass, id)
12
12
  without_proxy do
13
- ::Resque.constantize(klass).find(id).solr_index
13
+ constantize(klass).find(id).solr_index
14
14
  end
15
15
  end
16
16
  end
@@ -1,8 +1,8 @@
1
1
  require "sunspot/queue/helpers"
2
2
 
3
- module Sunspot::Queue
3
+ module Sunspot::Queue::Resque
4
4
  class RemovalJob
5
- extend Helpers
5
+ extend ::Sunspot::Queue::Helpers
6
6
 
7
7
  def self.queue
8
8
  :sunspot
@@ -1,13 +1,11 @@
1
- require "resque"
2
- require "sunspot/queue/index_job"
3
- require "sunspot/queue/removal_job"
4
-
5
1
  module Sunspot::Queue
6
2
  class SessionProxy
7
3
  attr_reader :session
4
+ attr_accessor :backend
8
5
 
9
- def initialize(session)
6
+ def initialize(session, backend)
10
7
  @session = session
8
+ @backend = backend
11
9
  end
12
10
 
13
11
  def index(*objects)
@@ -18,7 +16,7 @@ module Sunspot::Queue
18
16
  end
19
17
 
20
18
  objects.each do |object|
21
- ::Resque.enqueue(IndexJob, object.class.name, object.id)
19
+ @backend.index(object.class.name, object.id)
22
20
  end
23
21
  end
24
22
  alias :index! :index
@@ -34,7 +32,7 @@ module Sunspot::Queue
34
32
  # persisted and can safely be ignored since it shouldn't exist in the
35
33
  # search index.
36
34
  if object.id
37
- ::Resque.enqueue(RemovalJob, object.class.name, object.id)
35
+ @backend.remove(object.class.name, object.id)
38
36
  end
39
37
  end
40
38
  end
@@ -51,7 +49,7 @@ module Sunspot::Queue
51
49
 
52
50
  # Enqueues a removal job based on class and id.
53
51
  def remove_by_id(klass, id)
54
- ::Resque.enqueue(RemovalJob, klass.to_s, id)
52
+ @backend.remove(klass.to_s, id)
55
53
  end
56
54
  alias :remove_by_id! :remove_by_id
57
55
 
@@ -0,0 +1,9 @@
1
+ require "sunspot/queue"
2
+
3
+ module Sunspot::Queue
4
+ module Sidekiq
5
+ require "sunspot/queue/sidekiq/backend"
6
+ require "sunspot/queue/sidekiq/index_job"
7
+ require "sunspot/queue/sidekiq/removal_job"
8
+ end
9
+ end
@@ -0,0 +1,35 @@
1
+ require "sunspot/queue/sidekiq/index_job"
2
+ require "sunspot/queue/sidekiq/removal_job"
3
+
4
+ module Sunspot::Queue::Sidekiq
5
+ class Backend
6
+ attr_reader :configuration
7
+
8
+ def initialize(configuration = Sunspot::Queue.configuration)
9
+ @configuration = configuration
10
+ end
11
+
12
+ # Job needs to include Sidekiq::Worker
13
+ def enqueue(job, klass, id)
14
+ job.perform_async(klass, id)
15
+ end
16
+
17
+ def index(klass, id)
18
+ index_job.perform_async(klass, id)
19
+ end
20
+
21
+ def remove(klass, id)
22
+ removal_job.perform_async(klass, id)
23
+ end
24
+
25
+ private
26
+
27
+ def index_job
28
+ configuration.index_job || ::Sunspot::Queue::Sidekiq::IndexJob
29
+ end
30
+
31
+ def removal_job
32
+ configuration.removal_job || ::Sunspot::Queue::Sidekiq::RemovalJob
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,16 @@
1
+ require "sidekiq/worker"
2
+
3
+ module Sunspot::Queue::Sidekiq
4
+ class IndexJob
5
+ include ::Sunspot::Queue::Helpers
6
+ include ::Sidekiq::Worker
7
+
8
+ sidekiq_options :queue => "sunspot"
9
+
10
+ def perform(klass, id)
11
+ without_proxy do
12
+ constantize(klass).find(id).solr_index
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ require "sidekiq/worker"
2
+
3
+ module Sunspot::Queue::Sidekiq
4
+ class RemovalJob
5
+ include ::Sunspot::Queue::Helpers
6
+ include ::Sidekiq::Worker
7
+
8
+ sidekiq_options :queue => "sunspot"
9
+
10
+ def perform(klass, id)
11
+ without_proxy do
12
+ ::Sunspot.remove_by_id(klass, id)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,5 +1,5 @@
1
1
  module Sunspot
2
2
  module Queue
3
- VERSION = "0.9.1"
3
+ VERSION = "0.10.0"
4
4
  end
5
5
  end
@@ -0,0 +1,29 @@
1
+ require "spec_helper"
2
+
3
+ describe Sunspot::Queue::Configuration do
4
+ subject(:configuration) { described_class.new }
5
+
6
+ describe "#index_job" do
7
+ it "defaults to nil" do
8
+ configuration.index_job.should be_nil
9
+ end
10
+
11
+ it "can be set to a custom job" do
12
+ expect {
13
+ configuration.index_job = "CustomIndexJob"
14
+ }.to change(configuration, :index_job).to("CustomIndexJob")
15
+ end
16
+ end
17
+
18
+ describe "#removal_job" do
19
+ it "defaults to nil" do
20
+ configuration.removal_job.should be_nil
21
+ end
22
+
23
+ it "can be set to a custom job" do
24
+ expect do
25
+ configuration.removal_job = "CustomRemovalJob"
26
+ end.to change(configuration, :removal_job).to("CustomRemovalJob")
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,21 @@
1
+ require "spec_helper"
2
+ require "sunspot/queue/inline"
3
+
4
+ describe Sunspot::Queue::Inline::Backend, :backend => :inline do
5
+ it "indexes the class inline" do
6
+ expect do
7
+ Person.create(:name => "Steven Seagal")
8
+ commit
9
+ end.to change { Person.search.hits.size }.by(1)
10
+ end
11
+
12
+ it "removes the class inline" do
13
+ chuck = Person.create(:name => "Chuck Norris")
14
+ commit
15
+
16
+ expect do
17
+ chuck.destroy
18
+ commit
19
+ end.to change { Person.search.hits.size }.by(-1)
20
+ end
21
+ end
@@ -1,6 +1,6 @@
1
1
  require "spec_helper"
2
2
 
3
- describe "Queued Indexing" do
3
+ describe "Queued Indexing", :backend => :resque do
4
4
  # Given an active record model
5
5
  # When I save the model
6
6
  # Then the record should not be in solr
@@ -0,0 +1,41 @@
1
+ require "spec_helper"
2
+
3
+ describe "Sidekiq Integration", :backend => :sidekiq do
4
+ let(:index_job) { Sunspot::Queue::Sidekiq::IndexJob }
5
+ let(:removal_job) { Sunspot::Queue::Sidekiq::RemovalJob }
6
+
7
+ #
8
+ it "queues indexing on creation and update" do
9
+ jimmy = Person.create(:name => "Jimmy Olson")
10
+
11
+ index_job.jobs.size.should == 1
12
+ index_job.perform_work
13
+ commit
14
+
15
+ Person.search { fulltext "Olson" }.hits.size.should == 1
16
+
17
+ jimmy.update_attribute(:name, "James Bartholomew Olsen")
18
+ index_job.jobs.size.should == 1
19
+ index_job.perform_work
20
+ commit
21
+
22
+ Person.search { fulltext "Bartholomew" }.hits.size.should == 1
23
+ end
24
+
25
+ it "queues removal on destroy" do
26
+ pinky =
27
+ without_proxy do
28
+ Person.create(:name => "Pinky the Whiz Kid")
29
+ end
30
+ commit
31
+
32
+ Person.search.hits.size.should == 1
33
+
34
+ pinky.destroy
35
+ removal_job.jobs.size.should == 1
36
+ removal_job.perform_work
37
+ commit
38
+
39
+ Person.search.hits.size.should == 0
40
+ end
41
+ end
@@ -0,0 +1,27 @@
1
+ require "spec_helper"
2
+
3
+ describe Sunspot::Queue do
4
+
5
+ describe "#configuration" do
6
+ it "returns a default configuration" do
7
+ config = Sunspot::Queue.configuration
8
+ config.should be_kind_of(Sunspot::Queue::Configuration)
9
+ end
10
+
11
+ it "returns the same configuration when requested multiple times" do
12
+ config = Sunspot::Queue.configuration
13
+ Sunspot::Queue.configuration.should be(config)
14
+ Sunspot::Queue.configuration.should be(config)
15
+ end
16
+ end
17
+
18
+ describe "#configure(&blk)" do
19
+ it "yields the configuration to a block" do
20
+ config = Sunspot::Queue.configuration
21
+ expect do |blk|
22
+ Sunspot::Queue.configure(&blk)
23
+ end.to yield_with_args(config)
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,48 @@
1
+ require "spec_helper"
2
+
3
+ describe Sunspot::Queue::Resque::Backend do
4
+
5
+ # Mock ResqueJob
6
+ class CustomResqueJob
7
+ @queue = :custom_queue
8
+
9
+ def perform(klass, id)
10
+ end
11
+ end
12
+
13
+ subject(:backend) { described_class.new(configuration) }
14
+
15
+ let(:configuration) { ::Sunspot::Queue::Configuration.new }
16
+
17
+ describe "#index" do
18
+ it "uses the index job set in the global configuration" do
19
+ configuration.index_job = CustomResqueJob
20
+
21
+ expect do
22
+ backend.index(Person, 3)
23
+ end.to change { ResqueSpec.queue_for(CustomResqueJob).size }.by(1)
24
+ end
25
+
26
+ it "uses the default index job if one is not configured" do
27
+ expect do
28
+ backend.index(Person, 12)
29
+ end.to change { ResqueSpec.queue_for(Sunspot::Queue::Resque::IndexJob).size }.by(1)
30
+ end
31
+ end
32
+
33
+ describe "#remove" do
34
+ it "uses the removal job set in the global configuration" do
35
+ configuration.removal_job = CustomResqueJob
36
+
37
+ expect do
38
+ backend.remove(Person, 3)
39
+ end.to change { ResqueSpec.queue_for(CustomResqueJob).size }.by(1)
40
+ end
41
+
42
+ it "uses the default index job if one is not configured" do
43
+ expect do
44
+ backend.remove(Person, 12)
45
+ end.to change { ResqueSpec.queue_for(Sunspot::Queue::Resque::RemovalJob).size }.by(1)
46
+ end
47
+ end
48
+ end
@@ -1,13 +1,19 @@
1
1
  require "spec_helper"
2
2
 
3
- describe Sunspot::Queue::IndexJob do
3
+ describe Sunspot::Queue::Resque::IndexJob do
4
+ it "is linked to Sunspot::Queue::IndexJob for backwards compatibility" do
5
+ ::Sunspot::Queue::IndexJob.should == ::Sunspot::Queue::Resque::IndexJob
6
+ end
7
+
4
8
  context "ActiveRecord" do
9
+ let(:job) { Sunspot::Queue::Resque::IndexJob }
10
+
5
11
  it "indexes an ActiveRecord model" do
6
12
  # This will queue a job but we'll just ignore it to isolate the job
7
13
  person = Person.create(:name => "The Grandson")
8
14
 
9
15
  expect do
10
- Sunspot::Queue::IndexJob.perform(Person, person.id)
16
+ job.perform(Person, person.id)
11
17
  commit
12
18
  end.to change { Person.search.hits.size }.by(1)
13
19
 
@@ -17,13 +23,13 @@ describe Sunspot::Queue::IndexJob do
17
23
 
18
24
  it "raises an error if the record could not be found" do
19
25
  expect do
20
- Sunspot::Queue::IndexJob.perform(Person, 404)
26
+ job.perform(Person, 404)
21
27
  end.to raise_error(ActiveRecord::RecordNotFound)
22
28
  end
23
29
 
24
30
  it "maintains the existing proxy if there was an error" do
25
31
  expect do
26
- Sunspot::Queue::IndexJob.perform(Person, 404) rescue nil
32
+ job.perform(Person, 404) rescue nil
27
33
  end.to_not change { Sunspot.session }
28
34
  end
29
35
 
@@ -31,7 +37,7 @@ describe Sunspot::Queue::IndexJob do
31
37
  person = Person.create(:name => "The Grandson")
32
38
 
33
39
  expect do
34
- Sunspot::Queue::IndexJob.perform(Person, person.id)
40
+ job.perform(Person, person.id)
35
41
  end.to_not change { Person.search.hits.size }
36
42
 
37
43
  expect do
@@ -0,0 +1,26 @@
1
+ require "spec_helper"
2
+ require "sunspot/queue/resque"
3
+ require "sunspot/queue/helpers"
4
+
5
+ describe Sunspot::Queue::Resque::RemovalJob do
6
+ let(:job) { Sunspot::Queue::Resque::RemovalJob }
7
+
8
+ it "is linked to Sunspot::Queue::IndexJob for backwards compatibility" do
9
+ ::Sunspot::Queue::RemovalJob.should == ::Sunspot::Queue::Resque::RemovalJob
10
+ end
11
+
12
+ it "removes a job from the search index" do
13
+ person =
14
+ without_proxy do
15
+ Person.create(:name => "The Albino")
16
+ end
17
+ commit
18
+
19
+ Person.search.hits.size.should == 1
20
+
21
+ expect do
22
+ job.perform(Person, person.id)
23
+ commit
24
+ end.to change { Person.search.hits.size }.by(-1)
25
+ end
26
+ end
@@ -1,7 +1,8 @@
1
1
  require "spec_helper"
2
2
 
3
3
  describe Sunspot::Queue::SessionProxy do
4
- let(:proxy) { Sunspot::Queue::SessionProxy.new(mock) }
4
+ let(:backend) { mock }
5
+ let(:proxy) { Sunspot::Queue::SessionProxy.new(mock, backend) }
5
6
 
6
7
  context "#index" do
7
8
  it "enqueues a single job for each class" do
@@ -9,8 +10,7 @@ describe Sunspot::Queue::SessionProxy do
9
10
  Person.create(:name => "#{i} of 5")
10
11
  end
11
12
 
12
- Resque.should_receive(:enqueue).with do |job, klass, id|
13
- job.should == ::Sunspot::Queue::IndexJob
13
+ backend.should_receive(:index).with do |klass, _|
14
14
  klass.should == "Person"
15
15
  end.exactly(5).times
16
16
 
@@ -22,7 +22,7 @@ describe Sunspot::Queue::SessionProxy do
22
22
  Person.create(:name => "Clone ##{i}")
23
23
  end
24
24
 
25
- Resque.should_receive(:enqueue).exactly(2).times
25
+ backend.should_receive(:index).exactly(2).times
26
26
 
27
27
  proxy.index(people)
28
28
  end
@@ -30,7 +30,7 @@ describe Sunspot::Queue::SessionProxy do
30
30
  it "handles a single object being enqueued" do
31
31
  person = Person.create(:name => "Buttercup")
32
32
 
33
- Resque.should_receive(:enqueue).with do |_,_,id|
33
+ backend.should_receive(:index).with do |_, id|
34
34
  id.should == person.id
35
35
  end
36
36
 
@@ -62,7 +62,8 @@ describe Sunspot::Queue::SessionProxy do
62
62
  people = 2.times.map { |i| Person.new(:name => i) }
63
63
  people.first.save
64
64
 
65
- Resque.should_not_receive(:enqueue)
65
+ backend.should_not_receive(:index)
66
+
66
67
  expect do
67
68
  proxy.index(people)
68
69
  end.to raise_error(Sunspot::Queue::NotPersistedError)
@@ -75,8 +76,7 @@ describe Sunspot::Queue::SessionProxy do
75
76
  Person.create(:name => "#{i} of 5")
76
77
  end
77
78
 
78
- Resque.should_receive(:enqueue).with do |job, klass, id|
79
- job.should == ::Sunspot::Queue::RemovalJob
79
+ backend.should_receive(:remove).with do |klass, id|
80
80
  klass.should == "Person"
81
81
  end.exactly(5).times
82
82
 
@@ -88,7 +88,7 @@ describe Sunspot::Queue::SessionProxy do
88
88
  Person.create(:name => "Clone ##{i}")
89
89
  end
90
90
 
91
- Resque.should_receive(:enqueue).exactly(2).times
91
+ backend.should_receive(:remove).exactly(2).times
92
92
 
93
93
  proxy.remove(people)
94
94
  end
@@ -96,8 +96,7 @@ describe Sunspot::Queue::SessionProxy do
96
96
  it "handles a single object" do
97
97
  person = Person.create(:name => "Buttercup")
98
98
 
99
- Resque.should_receive(:enqueue).with do |job, _, id|
100
- job.should == ::Sunspot::Queue::RemovalJob
99
+ backend.should_receive(:remove).with do |_, id|
101
100
  id.should == person.id
102
101
  end
103
102
 
@@ -108,7 +107,7 @@ describe Sunspot::Queue::SessionProxy do
108
107
  people = 2.times.map { |i| Person.new(:name => "Thing #{i}") }
109
108
  people.first.save
110
109
 
111
- Resque.should_receive(:enqueue).once
110
+ backend.should_receive(:remove).once
112
111
 
113
112
  proxy.remove(people)
114
113
  end
@@ -0,0 +1,48 @@
1
+ require "spec_helper"
2
+
3
+ describe Sunspot::Queue::Sidekiq::Backend do
4
+
5
+ # Mock SidekiqJob
6
+ class CustomSidekiqJob
7
+ include ::Sidekiq::Worker
8
+
9
+ def perform(klass, id)
10
+ end
11
+ end
12
+
13
+ subject(:backend) { described_class.new(configuration) }
14
+
15
+ let(:configuration) { ::Sunspot::Queue::Configuration.new }
16
+
17
+ describe "#index" do
18
+ it "uses the index job set in the global configuration" do
19
+ configuration.index_job = CustomSidekiqJob
20
+
21
+ expect do
22
+ backend.index(Person, 9)
23
+ end.to change { CustomSidekiqJob.jobs.size }.by(1)
24
+ end
25
+
26
+ it "uses the default index job if one is not configured" do
27
+ expect do
28
+ backend.index(Person, 11)
29
+ end.to change { ::Sunspot::Queue::Sidekiq::IndexJob.jobs.size }.by(1)
30
+ end
31
+ end
32
+
33
+ describe "#remove" do
34
+ it "uses the removal job set in the global configuration" do
35
+ configuration.removal_job = CustomSidekiqJob
36
+
37
+ expect do
38
+ backend.remove(Person, 11)
39
+ end.to change { CustomSidekiqJob.jobs.size }.by(1)
40
+ end
41
+
42
+ it "uses the default removal job if one is not configured" do
43
+ expect do
44
+ backend.remove(Person, 11)
45
+ end.to change { ::Sunspot::Queue::Sidekiq::RemovalJob.jobs.size }.by(1)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,40 @@
1
+ require "spec_helper"
2
+
3
+ describe Sunspot::Queue::Sidekiq::IndexJob do
4
+ context "ActiveRecord" do
5
+ let(:job) { Sunspot::Queue::Sidekiq::IndexJob.new }
6
+
7
+ it "index an ActiveRecord model" do
8
+ person = Person.create(:name => "Dum Dum Dugen")
9
+
10
+ expect do
11
+ job.perform(Person, person.id)
12
+ commit
13
+ end.to change { Person.search.hits.size }.by(1)
14
+ end
15
+
16
+ it "raises an error if the record could not be found" do
17
+ expect do
18
+ job.perform(Person, 404)
19
+ end.to raise_error(ActiveRecord::RecordNotFound)
20
+ end
21
+
22
+ it "maintains the existing proxy if there was an error" do
23
+ expect do
24
+ job.perform(Person, 404) rescue nil
25
+ end.to_not change { Sunspot.session }
26
+ end
27
+
28
+ it "does not commit changes to the index" do
29
+ person = Person.create(:name => "Kato")
30
+
31
+ expect do
32
+ job.perform(Person, person.id)
33
+ end.to_not change { Person.search.hits.size }
34
+
35
+ expect do
36
+ commit
37
+ end.to change { Person.search.hits.size }
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,17 @@
1
+ require "spec_helper"
2
+
3
+ describe Sunspot::Queue::Sidekiq::RemovalJob do
4
+ let(:job) { Sunspot::Queue::Sidekiq::RemovalJob.new }
5
+
6
+ it "removes a job from the search index" do
7
+ person = Person.create(:name => "James 'Bucky' Barnes")
8
+ commit
9
+
10
+ Person.search.hits.size.should == 1
11
+
12
+ expect do
13
+ job.perform(Person, person.id)
14
+ commit
15
+ end.to change { Person.search.hits.size }.by(-1)
16
+ end
17
+ end
@@ -8,6 +8,14 @@ require "sunspot/rails"
8
8
  require "sunspot/solr/server"
9
9
  require "resque_spec"
10
10
 
11
+ # Neither is required when loading sunspot/queue
12
+ require "sunspot/queue/resque"
13
+ require "sunspot/queue/sidekiq"
14
+
15
+ # Sidekiq
16
+ require "sidekiq"
17
+ require "sidekiq/testing"
18
+
11
19
  # Configure ActiveRecord and Sunspot to work with ActiveRecord
12
20
  ActiveRecord::Base.establish_connection(
13
21
  :adapter => "sqlite3",
@@ -35,7 +43,11 @@ end
35
43
  RSpec.configure do |config|
36
44
  config.treat_symbols_as_metadata_keys_with_true_values = true
37
45
  config.run_all_when_everything_filtered = true
38
- config.filter_run :focus
46
+ config.order = "random"
47
+
48
+ # Requires supporting ruby files with custom matchers and macros, etc,
49
+ # in spec/support/ and its subdirectories.
50
+ Dir[File.expand_path("../support/*.rb", __FILE__)].each { |f| require(f) }
39
51
 
40
52
  config.include(Sunspot::Queue::Helpers)
41
53
  config.include(
@@ -49,11 +61,30 @@ RSpec.configure do |config|
49
61
  # Original sunspot session not wrapped in our proxy object
50
62
  session = Sunspot.session
51
63
 
64
+ # Clean up data between tests and reset the session
52
65
  config.before(:each) do
66
+ Sunspot.session = session
53
67
  session.remove_all!
68
+ end
69
+
70
+ config.before(:each, :backend => :resque) do
54
71
  ResqueSpec.reset!
55
72
 
56
- Sunspot.session = Sunspot::Queue::SessionProxy.new(session)
73
+ backend = Sunspot::Queue::Resque::Backend.new
74
+ Sunspot.session = Sunspot::Queue::SessionProxy.new(session, backend)
75
+ end
76
+
77
+ config.before(:each, :backend => :sidekiq) do
78
+ Sidekiq::Worker.clear_all
79
+
80
+ require "sunspot/queue/sidekiq"
81
+ backend = Sunspot::Queue::Sidekiq::Backend.new
82
+ Sunspot.session = Sunspot::Queue::SessionProxy.new(session, backend)
83
+ end
84
+
85
+ config.before(:each, :backend => :inline) do
86
+ backend = Sunspot::Queue::Inline::Backend.new
87
+ Sunspot.session = Sunspot::Queue::SessionProxy.new(session, backend)
57
88
  end
58
89
 
59
90
  # Configure Solr and run a server in the background for the duration of the
@@ -0,0 +1,19 @@
1
+ module Sidekiq
2
+ module Worker
3
+ module ClassMethods
4
+ def perform_work
5
+ if job = jobs.pop
6
+ self.new.perform(*Sidekiq.load_json(Sidekiq.dump_json(job["args"])))
7
+ end
8
+
9
+ true
10
+ end
11
+
12
+ def perform_all_the_work
13
+ while jobs.any?
14
+ perform_work
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sunspot-queue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 0.10.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,24 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-01 00:00:00.000000000 Z
12
+ date: 2013-01-23 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: sunspot_rails
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.3.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.3.0
14
30
  - !ruby/object:Gem::Dependency
15
31
  name: resque
16
32
  requirement: !ruby/object:Gem::Requirement
@@ -19,7 +35,7 @@ dependencies:
19
35
  - - ! '>='
20
36
  - !ruby/object:Gem::Version
21
37
  version: '0'
22
- type: :runtime
38
+ type: :development
23
39
  prerelease: false
24
40
  version_requirements: !ruby/object:Gem::Requirement
25
41
  none: false
@@ -28,21 +44,37 @@ dependencies:
28
44
  - !ruby/object:Gem::Version
29
45
  version: '0'
30
46
  - !ruby/object:Gem::Dependency
31
- name: sunspot_rails
47
+ name: sidekiq
32
48
  requirement: !ruby/object:Gem::Requirement
33
49
  none: false
34
50
  requirements:
35
51
  - - ! '>='
36
52
  - !ruby/object:Gem::Version
37
- version: 1.3.0
38
- type: :runtime
53
+ version: '0'
54
+ type: :development
39
55
  prerelease: false
40
56
  version_requirements: !ruby/object:Gem::Requirement
41
57
  none: false
42
58
  requirements:
43
59
  - - ! '>='
44
60
  - !ruby/object:Gem::Version
45
- version: 1.3.0
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: rake
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
46
78
  - !ruby/object:Gem::Dependency
47
79
  name: rspec
48
80
  requirement: !ruby/object:Gem::Requirement
@@ -50,7 +82,7 @@ dependencies:
50
82
  requirements:
51
83
  - - ~>
52
84
  - !ruby/object:Gem::Version
53
- version: 2.10.0
85
+ version: 2.11.0
54
86
  type: :development
55
87
  prerelease: false
56
88
  version_requirements: !ruby/object:Gem::Requirement
@@ -58,7 +90,7 @@ dependencies:
58
90
  requirements:
59
91
  - - ~>
60
92
  - !ruby/object:Gem::Version
61
- version: 2.10.0
93
+ version: 2.11.0
62
94
  - !ruby/object:Gem::Dependency
63
95
  name: resque_spec
64
96
  requirement: !ruby/object:Gem::Requirement
@@ -114,7 +146,7 @@ dependencies:
114
146
  requirements:
115
147
  - - ! '>='
116
148
  - !ruby/object:Gem::Version
117
- version: '0'
149
+ version: 3.2.0
118
150
  type: :development
119
151
  prerelease: false
120
152
  version_requirements: !ruby/object:Gem::Requirement
@@ -122,7 +154,7 @@ dependencies:
122
154
  requirements:
123
155
  - - ! '>='
124
156
  - !ruby/object:Gem::Version
125
- version: '0'
157
+ version: 3.2.0
126
158
  - !ruby/object:Gem::Dependency
127
159
  name: guard
128
160
  requirement: !ruby/object:Gem::Requirement
@@ -178,20 +210,39 @@ executables: []
178
210
  extensions: []
179
211
  extra_rdoc_files: []
180
212
  files:
213
+ - lib/sunspot/queue/configuration.rb
181
214
  - lib/sunspot/queue/helpers.rb
182
- - lib/sunspot/queue/index_job.rb
183
- - lib/sunspot/queue/removal_job.rb
215
+ - lib/sunspot/queue/inline/backend.rb
216
+ - lib/sunspot/queue/inline.rb
217
+ - lib/sunspot/queue/resque/backend.rb
218
+ - lib/sunspot/queue/resque/index_job.rb
219
+ - lib/sunspot/queue/resque/removal_job.rb
220
+ - lib/sunspot/queue/resque.rb
184
221
  - lib/sunspot/queue/session_proxy.rb
222
+ - lib/sunspot/queue/sidekiq/backend.rb
223
+ - lib/sunspot/queue/sidekiq/index_job.rb
224
+ - lib/sunspot/queue/sidekiq/removal_job.rb
225
+ - lib/sunspot/queue/sidekiq.rb
185
226
  - lib/sunspot/queue/version.rb
186
227
  - lib/sunspot/queue.rb
187
228
  - lib/sunspot-queue.rb
188
- - spec/index_job_spec.rb
229
+ - spec/configuration_spec.rb
230
+ - spec/inline/backend_spec.rb
189
231
  - spec/integration/indexing_spec.rb
190
- - spec/removal_job_spec.rb
232
+ - spec/integration/sidekiq_spec.rb
233
+ - spec/queue_spec.rb
234
+ - spec/resque/backend_spec.rb
235
+ - spec/resque/index_job_spec.rb
236
+ - spec/resque/removal_job_spec.rb
191
237
  - spec/session_proxy_spec.rb
238
+ - spec/sidekiq/backend_spec.rb
239
+ - spec/sidekiq/index_job_spec.rb
240
+ - spec/sidekiq/removal_job.rb
192
241
  - spec/spec_helper.rb
242
+ - spec/support/sidekiq.rb
193
243
  - LICENSE
194
244
  - README.md
245
+ - History.md
195
246
  homepage: https://github.com/gaffneyc/sunspot-queue
196
247
  licenses: []
197
248
  post_install_message:
@@ -204,12 +255,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
204
255
  - - ! '>='
205
256
  - !ruby/object:Gem::Version
206
257
  version: '0'
258
+ segments:
259
+ - 0
260
+ hash: -2557787847468836943
207
261
  required_rubygems_version: !ruby/object:Gem::Requirement
208
262
  none: false
209
263
  requirements:
210
264
  - - ! '>='
211
265
  - !ruby/object:Gem::Version
212
266
  version: '0'
267
+ segments:
268
+ - 0
269
+ hash: -2557787847468836943
213
270
  requirements: []
214
271
  rubyforge_project:
215
272
  rubygems_version: 1.8.24
@@ -1,20 +0,0 @@
1
- require "spec_helper"
2
- require "sunspot/queue/helpers"
3
-
4
- describe Sunspot::Queue::IndexJob do
5
- it "removes a job from the search index" do
6
- person =
7
- without_proxy do
8
- Person.create(:name => "The Albino").tap do
9
- commit
10
- end
11
- end
12
-
13
- Person.search.hits.size.should == 1
14
-
15
- expect do
16
- Sunspot::Queue::RemovalJob.perform(Person, person.id)
17
- commit
18
- end.to change { Person.search.hits.size }.by(-1)
19
- end
20
- end