opsb-delayed_job 2.0.3

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.
Files changed (42) hide show
  1. data/.gitignore +2 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.textile +213 -0
  4. data/Rakefile +46 -0
  5. data/VERSION +1 -0
  6. data/benchmarks.rb +33 -0
  7. data/contrib/delayed_job.monitrc +14 -0
  8. data/contrib/delayed_job_multiple.monitrc +23 -0
  9. data/delayed_job.gemspec +115 -0
  10. data/generators/delayed_job/delayed_job_generator.rb +22 -0
  11. data/generators/delayed_job/templates/migration.rb +21 -0
  12. data/generators/delayed_job/templates/script +5 -0
  13. data/init.rb +1 -0
  14. data/lib/delayed/backend/active_record.rb +90 -0
  15. data/lib/delayed/backend/base.rb +111 -0
  16. data/lib/delayed/backend/data_mapper.rb +125 -0
  17. data/lib/delayed/backend/mongo_mapper.rb +110 -0
  18. data/lib/delayed/command.rb +101 -0
  19. data/lib/delayed/message_sending.rb +22 -0
  20. data/lib/delayed/performable_method.rb +62 -0
  21. data/lib/delayed/railtie.rb +10 -0
  22. data/lib/delayed/recipes.rb +31 -0
  23. data/lib/delayed/tasks.rb +15 -0
  24. data/lib/delayed/worker.rb +183 -0
  25. data/lib/delayed_job.rb +14 -0
  26. data/rails/init.rb +5 -0
  27. data/recipes/delayed_job.rb +1 -0
  28. data/spec/backend/active_record_job_spec.rb +46 -0
  29. data/spec/backend/data_mapper_job_spec.rb +16 -0
  30. data/spec/backend/mongo_mapper_job_spec.rb +94 -0
  31. data/spec/backend/shared_backend_spec.rb +265 -0
  32. data/spec/delayed_method_spec.rb +59 -0
  33. data/spec/performable_method_spec.rb +42 -0
  34. data/spec/sample_jobs.rb +25 -0
  35. data/spec/setup/active_record.rb +33 -0
  36. data/spec/setup/data_mapper.rb +8 -0
  37. data/spec/setup/mongo_mapper.rb +17 -0
  38. data/spec/spec_helper.rb +26 -0
  39. data/spec/story_spec.rb +17 -0
  40. data/spec/worker_spec.rb +216 -0
  41. data/tasks/jobs.rake +1 -0
  42. metadata +256 -0
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ class StoryReader
4
+ def read(story)
5
+ "Epilog: #{story.tell}"
6
+ end
7
+ end
8
+
9
+ describe Delayed::PerformableMethod do
10
+
11
+ it "should ignore ActiveRecord::RecordNotFound errors because they are permanent" do
12
+ story = Story.create :text => 'Once upon...'
13
+ p = Delayed::PerformableMethod.new(story, :tell, [])
14
+ story.destroy
15
+ lambda { p.perform }.should_not raise_error
16
+ end
17
+
18
+ it "should store the object as string if its an active record" do
19
+ story = Story.create :text => 'Once upon...'
20
+ p = Delayed::PerformableMethod.new(story, :tell, [])
21
+ p.class.should == Delayed::PerformableMethod
22
+ p.object.should == "LOAD;Story;#{story.id}"
23
+ p.method.should == :tell
24
+ p.args.should == []
25
+ p.perform.should == 'Once upon...'
26
+ end
27
+
28
+ it "should allow class methods to be called on ActiveRecord models" do
29
+ p = Delayed::PerformableMethod.new(Story, :count, [])
30
+ lambda { p.send(:load, p.object) }.should_not raise_error
31
+ end
32
+
33
+ it "should store arguments as string if they are active record objects" do
34
+ story = Story.create :text => 'Once upon...'
35
+ reader = StoryReader.new
36
+ p = Delayed::PerformableMethod.new(reader, :read, [story])
37
+ p.class.should == Delayed::PerformableMethod
38
+ p.method.should == :read
39
+ p.args.should == ["LOAD;Story;#{story.id}"]
40
+ p.perform.should == 'Epilog: Once upon...'
41
+ end
42
+ end
@@ -0,0 +1,25 @@
1
+ class SimpleJob
2
+ cattr_accessor :runs; self.runs = 0
3
+ def perform; @@runs += 1; end
4
+ end
5
+
6
+ class ErrorJob
7
+ cattr_accessor :runs; self.runs = 0
8
+ def perform; raise 'did not work'; end
9
+ end
10
+
11
+ class LongRunningJob
12
+ def perform; sleep 250; end
13
+ end
14
+
15
+ class OnPermanentFailureJob < SimpleJob
16
+ def on_permanent_failure
17
+ end
18
+ end
19
+
20
+ module M
21
+ class ModuleJob
22
+ cattr_accessor :runs; self.runs = 0
23
+ def perform; @@runs += 1; end
24
+ end
25
+ end
@@ -0,0 +1,33 @@
1
+ require 'active_record'
2
+
3
+ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
4
+ ActiveRecord::Base.logger = Delayed::Worker.logger
5
+ ActiveRecord::Migration.verbose = false
6
+
7
+ ActiveRecord::Schema.define do
8
+ create_table :delayed_jobs, :force => true do |table|
9
+ table.integer :priority, :default => 0
10
+ table.integer :attempts, :default => 0
11
+ table.text :handler
12
+ table.text :last_error
13
+ table.datetime :run_at
14
+ table.datetime :locked_at
15
+ table.datetime :failed_at
16
+ table.string :locked_by
17
+ table.timestamps
18
+ end
19
+
20
+ add_index :delayed_jobs, [:priority, :run_at], :name => 'delayed_jobs_priority'
21
+
22
+ create_table :stories, :force => true do |table|
23
+ table.string :text
24
+ end
25
+ end
26
+
27
+ # Purely useful for test cases...
28
+ class Story < ActiveRecord::Base
29
+ def tell; text; end
30
+ def whatever(n, _); tell*n; end
31
+
32
+ handle_asynchronously :whatever
33
+ end
@@ -0,0 +1,8 @@
1
+ require 'dm-core'
2
+ require 'dm-validations'
3
+
4
+ require 'delayed/backend/data_mapper'
5
+
6
+ DataMapper.logger = Delayed::Worker.logger
7
+ DataMapper.setup(:default, "sqlite3::memory:")
8
+ DataMapper.auto_migrate!
@@ -0,0 +1,17 @@
1
+ require 'mongo_mapper'
2
+
3
+ MongoMapper.config = {
4
+ RAILS_ENV => {'database' => 'delayed_job'}
5
+ }
6
+ MongoMapper.connect RAILS_ENV
7
+
8
+ unless defined?(Story)
9
+ class Story
10
+ include ::MongoMapper::Document
11
+ def tell; text; end
12
+ def whatever(n, _); tell*n; end
13
+ def self.count; end
14
+
15
+ handle_asynchronously :whatever
16
+ end
17
+ end
@@ -0,0 +1,26 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
2
+
3
+ require 'rubygems'
4
+ require 'spec'
5
+ require 'logger'
6
+
7
+ require 'delayed_job'
8
+ require 'sample_jobs'
9
+
10
+ Delayed::Worker.logger = Logger.new('/tmp/dj.log')
11
+ RAILS_ENV = 'test'
12
+
13
+ # determine the available backends
14
+ BACKENDS = []
15
+ Dir.glob("#{File.dirname(__FILE__)}/setup/*.rb") do |backend|
16
+ begin
17
+ backend = File.basename(backend, '.rb')
18
+ require "setup/#{backend}"
19
+ require "backend/#{backend}_job_spec"
20
+ BACKENDS << backend.to_sym
21
+ rescue LoadError
22
+ puts "Unable to load #{backend} backend! #{$!}"
23
+ end
24
+ end
25
+
26
+ Delayed::Worker.backend = BACKENDS.first
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+
3
+ describe "A story" do
4
+
5
+ before(:all) do
6
+ @story = Story.create :text => "Once upon a time..."
7
+ end
8
+
9
+ it "should be shared" do
10
+ @story.tell.should == 'Once upon a time...'
11
+ end
12
+
13
+ it "should not return its result if it storytelling is delayed" do
14
+ @story.send_later(:tell).should_not == 'Once upon a time...'
15
+ end
16
+
17
+ end
@@ -0,0 +1,216 @@
1
+ require 'spec_helper'
2
+
3
+ describe Delayed::Worker do
4
+ def job_create(opts = {})
5
+ Delayed::Job.create(opts.merge(:payload_object => SimpleJob.new))
6
+ end
7
+
8
+ describe "backend=" do
9
+ it "should set the Delayed::Job constant to the backend" do
10
+ @clazz = Class.new
11
+ Delayed::Worker.backend = @clazz
12
+ Delayed::Job.should == @clazz
13
+ end
14
+
15
+ it "should set backend with a symbol" do
16
+ Delayed::Worker.backend = Class.new
17
+ Delayed::Worker.backend = :active_record
18
+ Delayed::Worker.backend.should == Delayed::Backend::ActiveRecord::Job
19
+ end
20
+ end
21
+
22
+ BACKENDS.each do |backend|
23
+ describe "with the #{backend} backend" do
24
+ before do
25
+ Delayed::Worker.backend = backend
26
+ Delayed::Job.delete_all
27
+
28
+ @worker = Delayed::Worker.new(:max_priority => nil, :min_priority => nil, :quiet => true)
29
+
30
+ SimpleJob.runs = 0
31
+ end
32
+
33
+ describe "running a job" do
34
+ it "should fail after Worker.max_run_time" do
35
+ begin
36
+ old_max_run_time = Delayed::Worker.max_run_time
37
+ Delayed::Worker.max_run_time = 1.second
38
+ @job = Delayed::Job.create :payload_object => LongRunningJob.new
39
+ @worker.run(@job)
40
+ @job.reload.last_error.should =~ /expired/
41
+ @job.attempts.should == 1
42
+ ensure
43
+ Delayed::Worker.max_run_time = old_max_run_time
44
+ end
45
+ end
46
+ end
47
+
48
+ context "worker prioritization" do
49
+ before(:each) do
50
+ @worker = Delayed::Worker.new(:max_priority => 5, :min_priority => -5, :quiet => true)
51
+ end
52
+
53
+ it "should only work_off jobs that are >= min_priority" do
54
+ SimpleJob.runs.should == 0
55
+
56
+ job_create(:priority => -10)
57
+ job_create(:priority => 0)
58
+ @worker.work_off
59
+
60
+ SimpleJob.runs.should == 1
61
+ end
62
+
63
+ it "should only work_off jobs that are <= max_priority" do
64
+ SimpleJob.runs.should == 0
65
+
66
+ job_create(:priority => 10)
67
+ job_create(:priority => 0)
68
+
69
+ @worker.work_off
70
+
71
+ SimpleJob.runs.should == 1
72
+ end
73
+ end
74
+
75
+ context "while running with locked and expired jobs" do
76
+ before(:each) do
77
+ @worker.name = 'worker1'
78
+ end
79
+
80
+ it "should not run jobs locked by another worker" do
81
+ job_create(:locked_by => 'other_worker', :locked_at => (Delayed::Job.db_time_now - 1.minutes))
82
+ lambda { @worker.work_off }.should_not change { SimpleJob.runs }
83
+ end
84
+
85
+ it "should run open jobs" do
86
+ job_create
87
+ lambda { @worker.work_off }.should change { SimpleJob.runs }.from(0).to(1)
88
+ end
89
+
90
+ it "should run expired jobs" do
91
+ expired_time = Delayed::Job.db_time_now - (1.minutes + Delayed::Worker.max_run_time)
92
+ job_create(:locked_by => 'other_worker', :locked_at => expired_time)
93
+ lambda { @worker.work_off }.should change { SimpleJob.runs }.from(0).to(1)
94
+ end
95
+
96
+ it "should run own jobs" do
97
+ job_create(:locked_by => @worker.name, :locked_at => (Delayed::Job.db_time_now - 1.minutes))
98
+ lambda { @worker.work_off }.should change { SimpleJob.runs }.from(0).to(1)
99
+ end
100
+ end
101
+
102
+ describe "failed jobs" do
103
+ before do
104
+ # reset defaults
105
+ Delayed::Worker.destroy_failed_jobs = true
106
+ Delayed::Worker.max_attempts = 25
107
+
108
+ @job = Delayed::Job.enqueue ErrorJob.new
109
+ end
110
+
111
+ it "should record last_error when destroy_failed_jobs = false, max_attempts = 1" do
112
+ Delayed::Worker.destroy_failed_jobs = false
113
+ Delayed::Worker.max_attempts = 1
114
+ @worker.run(@job)
115
+ @job.reload
116
+ @job.last_error.should =~ /did not work/
117
+ @job.last_error.should =~ /worker_spec.rb/
118
+ @job.attempts.should == 1
119
+ @job.failed_at.should_not be_nil
120
+ end
121
+
122
+ it "should re-schedule jobs after failing" do
123
+ @worker.run(@job)
124
+ @job.reload
125
+ @job.last_error.should =~ /did not work/
126
+ @job.last_error.should =~ /sample_jobs.rb:8:in `perform'/
127
+ @job.attempts.should == 1
128
+ @job.run_at.should > Delayed::Job.db_time_now - 10.minutes
129
+ @job.run_at.should < Delayed::Job.db_time_now + 10.minutes
130
+ end
131
+ end
132
+
133
+ context "reschedule" do
134
+ before do
135
+ @job = Delayed::Job.create :payload_object => SimpleJob.new
136
+ end
137
+
138
+ share_examples_for "any failure more than Worker.max_attempts times" do
139
+ context "when the job's payload has an #on_permanent_failure hook" do
140
+ before do
141
+ @job = Delayed::Job.create :payload_object => OnPermanentFailureJob.new
142
+ @job.payload_object.should respond_to :on_permanent_failure
143
+ end
144
+
145
+ it "should run that hook" do
146
+ @job.payload_object.should_receive :on_permanent_failure
147
+ Delayed::Worker.max_attempts.times { @worker.reschedule(@job) }
148
+ end
149
+ end
150
+
151
+ context "when the job's payload has no #on_permanent_failure hook" do
152
+ # It's a little tricky to test this in a straightforward way,
153
+ # because putting a should_not_receive expectation on
154
+ # @job.payload_object.on_permanent_failure makes that object
155
+ # incorrectly return true to
156
+ # payload_object.respond_to? :on_permanent_failure, which is what
157
+ # reschedule uses to decide whether to call on_permanent_failure.
158
+ # So instead, we just make sure that the payload_object as it
159
+ # already stands doesn't respond_to? on_permanent_failure, then
160
+ # shove it through the iterated reschedule loop and make sure we
161
+ # don't get a NoMethodError (caused by calling that nonexistent
162
+ # on_permanent_failure method).
163
+
164
+ before do
165
+ @job.payload_object.should_not respond_to(:on_permanent_failure)
166
+ end
167
+
168
+ it "should not try to run that hook" do
169
+ lambda do
170
+ Delayed::Worker.max_attempts.times { @worker.reschedule(@job) }
171
+ end.should_not raise_exception(NoMethodError)
172
+ end
173
+ end
174
+ end
175
+
176
+ context "and we want to destroy jobs" do
177
+ before do
178
+ Delayed::Worker.destroy_failed_jobs = true
179
+ end
180
+
181
+ it_should_behave_like "any failure more than Worker.max_attempts times"
182
+
183
+ it "should be destroyed if it failed more than Worker.max_attempts times" do
184
+ @job.should_receive(:destroy)
185
+ Delayed::Worker.max_attempts.times { @worker.reschedule(@job) }
186
+ end
187
+
188
+ it "should not be destroyed if failed fewer than Worker.max_attempts times" do
189
+ @job.should_not_receive(:destroy)
190
+ (Delayed::Worker.max_attempts - 1).times { @worker.reschedule(@job) }
191
+ end
192
+ end
193
+
194
+ context "and we don't want to destroy jobs" do
195
+ before do
196
+ Delayed::Worker.destroy_failed_jobs = false
197
+ end
198
+
199
+ it_should_behave_like "any failure more than Worker.max_attempts times"
200
+
201
+ it "should be failed if it failed more than Worker.max_attempts times" do
202
+ @job.reload.failed_at.should == nil
203
+ Delayed::Worker.max_attempts.times { @worker.reschedule(@job) }
204
+ @job.reload.failed_at.should_not == nil
205
+ end
206
+
207
+ it "should not be failed if it failed fewer than Worker.max_attempts times" do
208
+ (Delayed::Worker.max_attempts - 1).times { @worker.reschedule(@job) }
209
+ @job.reload.failed_at.should == nil
210
+ end
211
+ end
212
+ end
213
+ end
214
+ end
215
+
216
+ end
@@ -0,0 +1 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib', 'delayed', 'tasks'))
metadata ADDED
@@ -0,0 +1,256 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: opsb-delayed_job
3
+ version: !ruby/object:Gem::Version
4
+ hash: 9
5
+ prerelease: false
6
+ segments:
7
+ - 2
8
+ - 0
9
+ - 3
10
+ version: 2.0.3
11
+ platform: ruby
12
+ authors:
13
+ - Brandon Keepers
14
+ - "Tobias L\xC3\xBCtke"
15
+ autorequire:
16
+ bindir: bin
17
+ cert_chain: []
18
+
19
+ date: 2010-04-16 00:00:00 +01:00
20
+ default_executable:
21
+ dependencies:
22
+ - !ruby/object:Gem::Dependency
23
+ name: daemons
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ">="
29
+ - !ruby/object:Gem::Version
30
+ hash: 3
31
+ segments:
32
+ - 0
33
+ version: "0"
34
+ type: :runtime
35
+ version_requirements: *id001
36
+ - !ruby/object:Gem::Dependency
37
+ name: rspec
38
+ prerelease: false
39
+ requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ hash: 3
45
+ segments:
46
+ - 0
47
+ version: "0"
48
+ type: :development
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: sqlite3-ruby
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
54
+ none: false
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ hash: 3
59
+ segments:
60
+ - 0
61
+ version: "0"
62
+ type: :development
63
+ version_requirements: *id003
64
+ - !ruby/object:Gem::Dependency
65
+ name: mongo_mapper
66
+ prerelease: false
67
+ requirement: &id004 !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ hash: 3
73
+ segments:
74
+ - 0
75
+ version: "0"
76
+ type: :development
77
+ version_requirements: *id004
78
+ - !ruby/object:Gem::Dependency
79
+ name: dm-core
80
+ prerelease: false
81
+ requirement: &id005 !ruby/object:Gem::Requirement
82
+ none: false
83
+ requirements:
84
+ - - ">="
85
+ - !ruby/object:Gem::Version
86
+ hash: 3
87
+ segments:
88
+ - 0
89
+ version: "0"
90
+ type: :development
91
+ version_requirements: *id005
92
+ - !ruby/object:Gem::Dependency
93
+ name: dm-observer
94
+ prerelease: false
95
+ requirement: &id006 !ruby/object:Gem::Requirement
96
+ none: false
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ hash: 3
101
+ segments:
102
+ - 0
103
+ version: "0"
104
+ type: :development
105
+ version_requirements: *id006
106
+ - !ruby/object:Gem::Dependency
107
+ name: dm-aggregates
108
+ prerelease: false
109
+ requirement: &id007 !ruby/object:Gem::Requirement
110
+ none: false
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ hash: 3
115
+ segments:
116
+ - 0
117
+ version: "0"
118
+ type: :development
119
+ version_requirements: *id007
120
+ - !ruby/object:Gem::Dependency
121
+ name: dm-validations
122
+ prerelease: false
123
+ requirement: &id008 !ruby/object:Gem::Requirement
124
+ none: false
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ hash: 3
129
+ segments:
130
+ - 0
131
+ version: "0"
132
+ type: :development
133
+ version_requirements: *id008
134
+ - !ruby/object:Gem::Dependency
135
+ name: do_sqlite3
136
+ prerelease: false
137
+ requirement: &id009 !ruby/object:Gem::Requirement
138
+ none: false
139
+ requirements:
140
+ - - ">="
141
+ - !ruby/object:Gem::Version
142
+ hash: 3
143
+ segments:
144
+ - 0
145
+ version: "0"
146
+ type: :development
147
+ version_requirements: *id009
148
+ - !ruby/object:Gem::Dependency
149
+ name: database_cleaner
150
+ prerelease: false
151
+ requirement: &id010 !ruby/object:Gem::Requirement
152
+ none: false
153
+ requirements:
154
+ - - ">="
155
+ - !ruby/object:Gem::Version
156
+ hash: 3
157
+ segments:
158
+ - 0
159
+ version: "0"
160
+ type: :development
161
+ version_requirements: *id010
162
+ description: |-
163
+ Delayed_job (or DJ) encapsulates the common pattern of asynchronously executing longer tasks in the background. It is a direct extraction from Shopify where the job table is responsible for a multitude of core tasks.
164
+
165
+ This gem is collectiveidea's fork (http://github.com/collectiveidea/delayed_job).
166
+ email: tobi@leetsoft.com
167
+ executables: []
168
+
169
+ extensions: []
170
+
171
+ extra_rdoc_files:
172
+ - README.textile
173
+ files:
174
+ - .gitignore
175
+ - MIT-LICENSE
176
+ - README.textile
177
+ - Rakefile
178
+ - VERSION
179
+ - benchmarks.rb
180
+ - contrib/delayed_job.monitrc
181
+ - contrib/delayed_job_multiple.monitrc
182
+ - delayed_job.gemspec
183
+ - generators/delayed_job/delayed_job_generator.rb
184
+ - generators/delayed_job/templates/migration.rb
185
+ - generators/delayed_job/templates/script
186
+ - init.rb
187
+ - lib/delayed/backend/active_record.rb
188
+ - lib/delayed/backend/base.rb
189
+ - lib/delayed/backend/data_mapper.rb
190
+ - lib/delayed/backend/mongo_mapper.rb
191
+ - lib/delayed/command.rb
192
+ - lib/delayed/message_sending.rb
193
+ - lib/delayed/performable_method.rb
194
+ - lib/delayed/railtie.rb
195
+ - lib/delayed/recipes.rb
196
+ - lib/delayed/tasks.rb
197
+ - lib/delayed/worker.rb
198
+ - lib/delayed_job.rb
199
+ - rails/init.rb
200
+ - recipes/delayed_job.rb
201
+ - spec/backend/active_record_job_spec.rb
202
+ - spec/backend/data_mapper_job_spec.rb
203
+ - spec/backend/mongo_mapper_job_spec.rb
204
+ - spec/backend/shared_backend_spec.rb
205
+ - spec/delayed_method_spec.rb
206
+ - spec/performable_method_spec.rb
207
+ - spec/sample_jobs.rb
208
+ - spec/setup/active_record.rb
209
+ - spec/setup/data_mapper.rb
210
+ - spec/setup/mongo_mapper.rb
211
+ - spec/spec_helper.rb
212
+ - spec/story_spec.rb
213
+ - spec/worker_spec.rb
214
+ - tasks/jobs.rake
215
+ has_rdoc: true
216
+ homepage: http://github.com/collectiveidea/delayed_job
217
+ licenses: []
218
+
219
+ post_install_message:
220
+ rdoc_options:
221
+ - --main
222
+ - README.textile
223
+ - --inline-source
224
+ - --line-numbers
225
+ require_paths:
226
+ - lib
227
+ required_ruby_version: !ruby/object:Gem::Requirement
228
+ none: false
229
+ requirements:
230
+ - - ">="
231
+ - !ruby/object:Gem::Version
232
+ hash: 3
233
+ segments:
234
+ - 0
235
+ version: "0"
236
+ required_rubygems_version: !ruby/object:Gem::Requirement
237
+ none: false
238
+ requirements:
239
+ - - ">="
240
+ - !ruby/object:Gem::Version
241
+ hash: 3
242
+ segments:
243
+ - 0
244
+ version: "0"
245
+ requirements: []
246
+
247
+ rubyforge_project:
248
+ rubygems_version: 1.3.7
249
+ signing_key:
250
+ specification_version: 3
251
+ summary: Database-backed asynchronous priority queue system -- Extracted from Shopify
252
+ test_files:
253
+ - spec/delayed_method_spec.rb
254
+ - spec/performable_method_spec.rb
255
+ - spec/story_spec.rb
256
+ - spec/worker_spec.rb