delayed_job 2.1.0.pre → 2.1.0.pre2
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.
- data/README.textile +1 -16
- data/lib/delayed/backend/active_record.rb +12 -5
- data/lib/delayed/backend/base.rb +12 -3
- data/lib/delayed/backend/shared_spec.rb +472 -0
- data/lib/delayed/command.rb +4 -4
- data/lib/delayed/message_sending.rb +8 -6
- data/lib/delayed/performable_method.rb +9 -1
- data/lib/delayed/tasks.rb +2 -6
- data/lib/delayed/worker.rb +12 -12
- data/lib/delayed_job.rb +0 -4
- data/spec/{backend/active_record_job_spec.rb → active_record_job_spec.rb} +1 -11
- data/spec/message_sending_spec.rb +8 -1
- data/spec/performable_method_spec.rb +19 -1
- data/spec/sample_jobs.rb +36 -0
- data/spec/spec_helper.rb +35 -13
- data/spec/worker_spec.rb +14 -191
- data/spec/yaml_ext_spec.rb +16 -0
- metadata +24 -103
- data/.gitignore +0 -2
- data/Rakefile +0 -53
- data/VERSION +0 -1
- data/benchmarks.rb +0 -33
- data/delayed_job.gemspec +0 -125
- data/lib/delayed/backend/couch_rest.rb +0 -109
- data/lib/delayed/backend/data_mapper.rb +0 -121
- data/lib/delayed/backend/mongo_mapper.rb +0 -106
- data/spec/backend/couch_rest_job_spec.rb +0 -15
- data/spec/backend/data_mapper_job_spec.rb +0 -16
- data/spec/backend/mongo_mapper_job_spec.rb +0 -94
- data/spec/backend/shared_backend_spec.rb +0 -273
- data/spec/setup/active_record.rb +0 -33
- data/spec/setup/couch_rest.rb +0 -7
- data/spec/setup/data_mapper.rb +0 -8
- data/spec/setup/mongo_mapper.rb +0 -17
@@ -1,273 +0,0 @@
|
|
1
|
-
class NamedJob < Struct.new(:perform)
|
2
|
-
def display_name
|
3
|
-
'named_job'
|
4
|
-
end
|
5
|
-
end
|
6
|
-
|
7
|
-
shared_examples_for 'a backend' do
|
8
|
-
def create_job(opts = {})
|
9
|
-
@backend.create(opts.merge(:payload_object => SimpleJob.new))
|
10
|
-
end
|
11
|
-
|
12
|
-
before do
|
13
|
-
Delayed::Worker.max_priority = nil
|
14
|
-
Delayed::Worker.min_priority = nil
|
15
|
-
SimpleJob.runs = 0
|
16
|
-
end
|
17
|
-
|
18
|
-
it "should set run_at automatically if not set" do
|
19
|
-
@backend.create(:payload_object => ErrorJob.new ).run_at.should_not be_nil
|
20
|
-
end
|
21
|
-
|
22
|
-
it "should not set run_at automatically if already set" do
|
23
|
-
later = @backend.db_time_now + 5.minutes
|
24
|
-
@backend.create(:payload_object => ErrorJob.new, :run_at => later).run_at.should be_close(later, 1)
|
25
|
-
end
|
26
|
-
|
27
|
-
it "should raise ArgumentError when handler doesn't respond_to :perform" do
|
28
|
-
lambda { @backend.enqueue(Object.new) }.should raise_error(ArgumentError)
|
29
|
-
end
|
30
|
-
|
31
|
-
it "should increase count after enqueuing items" do
|
32
|
-
@backend.enqueue SimpleJob.new
|
33
|
-
@backend.count.should == 1
|
34
|
-
end
|
35
|
-
|
36
|
-
it "should be able to set priority when enqueuing items" do
|
37
|
-
@job = @backend.enqueue SimpleJob.new, 5
|
38
|
-
@job.priority.should == 5
|
39
|
-
end
|
40
|
-
|
41
|
-
it "should be able to set run_at when enqueuing items" do
|
42
|
-
later = @backend.db_time_now + 5.minutes
|
43
|
-
@job = @backend.enqueue SimpleJob.new, 5, later
|
44
|
-
@job.run_at.should be_close(later, 1)
|
45
|
-
end
|
46
|
-
|
47
|
-
it "should work with jobs in modules" do
|
48
|
-
M::ModuleJob.runs = 0
|
49
|
-
job = @backend.enqueue M::ModuleJob.new
|
50
|
-
lambda { job.invoke_job }.should change { M::ModuleJob.runs }.from(0).to(1)
|
51
|
-
end
|
52
|
-
|
53
|
-
describe "payload_object" do
|
54
|
-
it "should raise a DeserializationError when the job class is totally unknown" do
|
55
|
-
job = @backend.new :handler => "--- !ruby/object:JobThatDoesNotExist {}"
|
56
|
-
lambda { job.payload_object }.should raise_error(Delayed::Backend::DeserializationError)
|
57
|
-
end
|
58
|
-
|
59
|
-
it "should raise a DeserializationError when the job struct is totally unknown" do
|
60
|
-
job = @backend.new :handler => "--- !ruby/struct:StructThatDoesNotExist {}"
|
61
|
-
lambda { job.payload_object }.should raise_error(Delayed::Backend::DeserializationError)
|
62
|
-
end
|
63
|
-
|
64
|
-
it "should autoload classes that are unknown at runtime" do
|
65
|
-
job = @backend.new :handler => "--- !ruby/object:Autoloaded::Clazz {}"
|
66
|
-
lambda { job.payload_object }.should_not raise_error(Delayed::Backend::DeserializationError)
|
67
|
-
end
|
68
|
-
|
69
|
-
it "should autoload structs that are unknown at runtime" do
|
70
|
-
job = @backend.new :handler => "--- !ruby/struct:Autoloaded::Struct {}"
|
71
|
-
lambda { job.payload_object }.should_not raise_error(Delayed::Backend::DeserializationError)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
describe "find_available" do
|
76
|
-
it "should not find failed jobs" do
|
77
|
-
@job = create_job :attempts => 50, :failed_at => @backend.db_time_now
|
78
|
-
@backend.find_available('worker', 5, 1.second).should_not include(@job)
|
79
|
-
end
|
80
|
-
|
81
|
-
it "should not find jobs scheduled for the future" do
|
82
|
-
@job = create_job :run_at => (@backend.db_time_now + 1.minute)
|
83
|
-
@backend.find_available('worker', 5, 4.hours).should_not include(@job)
|
84
|
-
end
|
85
|
-
|
86
|
-
it "should not find jobs locked by another worker" do
|
87
|
-
@job = create_job(:locked_by => 'other_worker', :locked_at => @backend.db_time_now - 1.minute)
|
88
|
-
@backend.find_available('worker', 5, 4.hours).should_not include(@job)
|
89
|
-
end
|
90
|
-
|
91
|
-
it "should find open jobs" do
|
92
|
-
@job = create_job
|
93
|
-
@backend.find_available('worker', 5, 4.hours).should include(@job)
|
94
|
-
end
|
95
|
-
|
96
|
-
it "should find expired jobs" do
|
97
|
-
@job = create_job(:locked_by => 'worker', :locked_at => @backend.db_time_now - 2.minutes)
|
98
|
-
@backend.find_available('worker', 5, 1.minute).should include(@job)
|
99
|
-
end
|
100
|
-
|
101
|
-
it "should find own jobs" do
|
102
|
-
@job = create_job(:locked_by => 'worker', :locked_at => (@backend.db_time_now - 1.minutes))
|
103
|
-
@backend.find_available('worker', 5, 4.hours).should include(@job)
|
104
|
-
end
|
105
|
-
|
106
|
-
it "should find only the right amount of jobs" do
|
107
|
-
10.times { create_job }
|
108
|
-
@backend.find_available('worker', 7, 4.hours).should have(7).jobs
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
context "when another worker is already performing an task, it" do
|
113
|
-
|
114
|
-
before :each do
|
115
|
-
@job = @backend.create :payload_object => SimpleJob.new, :locked_by => 'worker1', :locked_at => @backend.db_time_now - 5.minutes
|
116
|
-
end
|
117
|
-
|
118
|
-
it "should not allow a second worker to get exclusive access" do
|
119
|
-
@job.lock_exclusively!(4.hours, 'worker2').should == false
|
120
|
-
end
|
121
|
-
|
122
|
-
it "should allow a second worker to get exclusive access if the timeout has passed" do
|
123
|
-
@job.lock_exclusively!(1.minute, 'worker2').should == true
|
124
|
-
end
|
125
|
-
|
126
|
-
it "should be able to get access to the task if it was started more then max_age ago" do
|
127
|
-
@job.locked_at = 5.hours.ago
|
128
|
-
@job.save
|
129
|
-
|
130
|
-
@job.lock_exclusively! 4.hours, 'worker2'
|
131
|
-
@job.reload
|
132
|
-
@job.locked_by.should == 'worker2'
|
133
|
-
@job.locked_at.should > 1.minute.ago
|
134
|
-
end
|
135
|
-
|
136
|
-
it "should not be found by another worker" do
|
137
|
-
@backend.find_available('worker2', 1, 6.minutes).length.should == 0
|
138
|
-
end
|
139
|
-
|
140
|
-
it "should be found by another worker if the time has expired" do
|
141
|
-
@backend.find_available('worker2', 1, 4.minutes).length.should == 1
|
142
|
-
end
|
143
|
-
|
144
|
-
it "should be able to get exclusive access again when the worker name is the same" do
|
145
|
-
@job.lock_exclusively!(5.minutes, 'worker1').should be_true
|
146
|
-
@job.lock_exclusively!(5.minutes, 'worker1').should be_true
|
147
|
-
@job.lock_exclusively!(5.minutes, 'worker1').should be_true
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
context "when another worker has worked on a task since the job was found to be available, it" do
|
152
|
-
|
153
|
-
before :each do
|
154
|
-
@job = @backend.create :payload_object => SimpleJob.new
|
155
|
-
@job_copy_for_worker_2 = @backend.find(@job.id)
|
156
|
-
end
|
157
|
-
|
158
|
-
it "should not allow a second worker to get exclusive access if already successfully processed by worker1" do
|
159
|
-
@job.destroy
|
160
|
-
@job_copy_for_worker_2.lock_exclusively!(4.hours, 'worker2').should == false
|
161
|
-
end
|
162
|
-
|
163
|
-
it "should not allow a second worker to get exclusive access if failed to be processed by worker1 and run_at time is now in future (due to backing off behaviour)" do
|
164
|
-
@job.update_attributes(:attempts => 1, :run_at => 1.day.from_now)
|
165
|
-
@job_copy_for_worker_2.lock_exclusively!(4.hours, 'worker2').should == false
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
context "#name" do
|
170
|
-
it "should be the class name of the job that was enqueued" do
|
171
|
-
@backend.create(:payload_object => ErrorJob.new ).name.should == 'ErrorJob'
|
172
|
-
end
|
173
|
-
|
174
|
-
it "should be the method that will be called if its a performable method object" do
|
175
|
-
job = @backend.new(:payload_object => NamedJob.new)
|
176
|
-
job.name.should == 'named_job'
|
177
|
-
end
|
178
|
-
|
179
|
-
it "should be the instance method that will be called if its a performable method object" do
|
180
|
-
@job = Story.create(:text => "...").delay.save
|
181
|
-
@job.name.should == 'Story#save'
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
context "worker prioritization" do
|
186
|
-
before(:each) do
|
187
|
-
Delayed::Worker.max_priority = nil
|
188
|
-
Delayed::Worker.min_priority = nil
|
189
|
-
end
|
190
|
-
|
191
|
-
it "should fetch jobs ordered by priority" do
|
192
|
-
10.times { @backend.enqueue SimpleJob.new, rand(10) }
|
193
|
-
jobs = @backend.find_available('worker', 10)
|
194
|
-
jobs.size.should == 10
|
195
|
-
jobs.each_cons(2) do |a, b|
|
196
|
-
a.priority.should <= b.priority
|
197
|
-
end
|
198
|
-
end
|
199
|
-
|
200
|
-
it "should only find jobs greater than or equal to min priority" do
|
201
|
-
min = 5
|
202
|
-
Delayed::Worker.min_priority = min
|
203
|
-
10.times {|i| @backend.enqueue SimpleJob.new, i }
|
204
|
-
jobs = @backend.find_available('worker', 10)
|
205
|
-
jobs.each {|job| job.priority.should >= min}
|
206
|
-
end
|
207
|
-
|
208
|
-
it "should only find jobs less than or equal to max priority" do
|
209
|
-
max = 5
|
210
|
-
Delayed::Worker.max_priority = max
|
211
|
-
10.times {|i| @backend.enqueue SimpleJob.new, i }
|
212
|
-
jobs = @backend.find_available('worker', 10)
|
213
|
-
jobs.each {|job| job.priority.should <= max}
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
context "clear_locks!" do
|
218
|
-
before do
|
219
|
-
@job = create_job(:locked_by => 'worker', :locked_at => @backend.db_time_now)
|
220
|
-
end
|
221
|
-
|
222
|
-
it "should clear locks for the given worker" do
|
223
|
-
@backend.clear_locks!('worker')
|
224
|
-
@backend.find_available('worker2', 5, 1.minute).should include(@job)
|
225
|
-
end
|
226
|
-
|
227
|
-
it "should not clear locks for other workers" do
|
228
|
-
@backend.clear_locks!('worker1')
|
229
|
-
@backend.find_available('worker1', 5, 1.minute).should_not include(@job)
|
230
|
-
end
|
231
|
-
end
|
232
|
-
|
233
|
-
context "unlock" do
|
234
|
-
before do
|
235
|
-
@job = create_job(:locked_by => 'worker', :locked_at => @backend.db_time_now)
|
236
|
-
end
|
237
|
-
|
238
|
-
it "should clear locks" do
|
239
|
-
@job.unlock
|
240
|
-
@job.locked_by.should be_nil
|
241
|
-
@job.locked_at.should be_nil
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
|
-
context "large handler" do
|
246
|
-
before do
|
247
|
-
text = "Lorem ipsum dolor sit amet. " * 1000
|
248
|
-
@job = @backend.enqueue Delayed::PerformableMethod.new(text, :length, {})
|
249
|
-
end
|
250
|
-
|
251
|
-
it "should have an id" do
|
252
|
-
@job.id.should_not be_nil
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
|
-
describe "yaml serialization" do
|
257
|
-
it "should reload changed attributes" do
|
258
|
-
job = @backend.enqueue SimpleJob.new
|
259
|
-
yaml = job.to_yaml
|
260
|
-
job.priority = 99
|
261
|
-
job.save
|
262
|
-
YAML.load(yaml).priority.should == 99
|
263
|
-
end
|
264
|
-
|
265
|
-
it "should ignore destroyed records" do
|
266
|
-
job = @backend.enqueue SimpleJob.new
|
267
|
-
yaml = job.to_yaml
|
268
|
-
job.destroy
|
269
|
-
lambda { YAML.load(yaml).should be_nil }.should_not raise_error
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
end
|
data/spec/setup/active_record.rb
DELETED
@@ -1,33 +0,0 @@
|
|
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
|
data/spec/setup/couch_rest.rb
DELETED
data/spec/setup/data_mapper.rb
DELETED
data/spec/setup/mongo_mapper.rb
DELETED
@@ -1,17 +0,0 @@
|
|
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
|