delayed_job 2.1.1 → 2.1.2

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.
@@ -24,7 +24,7 @@ gem 'delayed_job'
24
24
 
25
25
  After delayed_job is installed, you will need to setup the backend.
26
26
 
27
- h2. Backends
27
+ h3. Backends
28
28
 
29
29
  delayed_job supports multiple backends for storing the job queue. "See the wiki for other backends":http://wiki.github.com/collectiveidea/delayed_job/backends besides Active Record.
30
30
 
@@ -41,10 +41,10 @@ Call @.delay.method(params)@ on any object and it will be processed in the backg
41
41
 
42
42
  <pre>
43
43
  # without delayed_job
44
- Notifier.deliver_signup(@user)
44
+ @user.activate!(@device)
45
45
 
46
46
  # with delayed_job
47
- Notifier.delay.signup(@user)
47
+ @user.delay.activate!(@device)
48
48
  </pre>
49
49
 
50
50
  If a method should always be run in the background, you can call @#handle_asynchronously@ after the method declaration:
@@ -94,6 +94,20 @@ class LongTasks
94
94
  end
95
95
  </pre>
96
96
 
97
+ h3. Rails 3 Mailers
98
+
99
+ Due to how mailers are implemented in Rails 3, we had to do a little work around to get delayed_job to work.
100
+
101
+ <pre>
102
+ # without delayed_job
103
+ Notifier.signup(@user).deliver
104
+
105
+ # with delayed_job
106
+ Notifier.delay.signup(@user)
107
+ </pre>
108
+
109
+ Remove the @.deliver@ method to make it work. It's not ideal, but it's the best we could do for now.
110
+
97
111
  h2. Running Jobs
98
112
 
99
113
  @script/delayed_job@ can be used to manage a background process which will start working off jobs. Make sure you've run `script/generate delayed_job`.
@@ -16,6 +16,10 @@ module Delayed
16
16
  }
17
17
  scope :by_priority, order('priority ASC, run_at ASC')
18
18
 
19
+ scope :locked_by_worker, lambda{|worker_name, max_run_time|
20
+ where(['locked_by = ? AND locked_at > ?', worker_name, db_time_now - max_run_time])
21
+ }
22
+
19
23
  def self.before_fork
20
24
  ::ActiveRecord::Base.clear_all_connections!
21
25
  end
@@ -29,37 +33,25 @@ module Delayed
29
33
  update_all("locked_by = null, locked_at = null", ["locked_by = ?", worker_name])
30
34
  end
31
35
 
32
- # Find a few candidate jobs to run (in case some immediately get locked by others).
33
- def self.find_available(worker_name, limit = 5, max_run_time = Worker.max_run_time)
36
+ def self.jobs_available_to_worker(worker_name, max_run_time)
34
37
  scope = self.ready_to_run(worker_name, max_run_time)
35
38
  scope = scope.scoped(:conditions => ['priority >= ?', Worker.min_priority]) if Worker.min_priority
36
39
  scope = scope.scoped(:conditions => ['priority <= ?', Worker.max_priority]) if Worker.max_priority
40
+ scope.by_priority
41
+ end
37
42
 
43
+ # Reserve a single job in a single update query. This causes workers to serialize on the
44
+ # database and avoids contention.
45
+ def self.reserve(worker, max_run_time = Worker.max_run_time)
46
+ affected_rows = 0
38
47
  ::ActiveRecord::Base.silence do
39
- scope.by_priority.all(:limit => limit)
48
+ affected_rows = jobs_available_to_worker(worker.name, max_run_time).limit(1).update_all(["locked_at = ?, locked_by = ?", db_time_now, worker.name])
40
49
  end
41
- end
42
50
 
43
- # Lock this job for this worker.
44
- # Returns true if we have the lock, false otherwise.
45
- def lock_exclusively!(max_run_time, worker)
46
- now = self.class.db_time_now
47
- affected_rows = if locked_by != worker
48
- # We don't own this job so we will update the locked_by name and the locked_at
49
- self.class.update_all(["locked_at = ?, locked_by = ?", now, worker], ["id = ? and (locked_at is null or locked_at < ?) and (run_at <= ?)", id, (now - max_run_time.to_i), now])
50
- else
51
- # We already own this job, this may happen if the job queue crashes.
52
- # Simply resume and update the locked_at
53
- self.class.update_all(["locked_at = ?", now], ["id = ? and locked_by = ?", id, worker])
54
- end
55
51
  if affected_rows == 1
56
- self.locked_at = now
57
- self.locked_by = worker
58
- self.locked_at_will_change!
59
- self.locked_by_will_change!
60
- return true
52
+ locked_by_worker(worker.name, max_run_time).first
61
53
  else
62
- return false
54
+ nil
63
55
  end
64
56
  end
65
57
 
@@ -10,14 +10,14 @@ module Delayed
10
10
  def enqueue(*args)
11
11
  options = {
12
12
  :priority => Delayed::Worker.default_priority
13
- }
14
-
15
- if args.size == 1 && args.first.is_a?(Hash)
16
- options.merge!(args.first)
17
- else
18
- options[:payload_object] = args.shift
19
- options[:priority] = args.first || options[:priority]
20
- options[:run_at] = args[1]
13
+ }.merge!(args.extract_options!)
14
+
15
+ options[:payload_object] ||= args.shift
16
+
17
+ if args.size > 0
18
+ warn "[DEPRECATION] Passing multiple arguments to `#enqueue` is deprecated. Pass a hash with :priority and :run_at."
19
+ options[:priority] = args.first || options[:priority]
20
+ options[:run_at] = args[1]
21
21
  end
22
22
 
23
23
  unless options[:payload_object].respond_to?(:perform)
@@ -109,7 +109,11 @@ module Delayed
109
109
  payload_object.reschedule_at(self.class.db_time_now, attempts) :
110
110
  self.class.db_time_now + (attempts ** 4) + 5
111
111
  end
112
-
112
+
113
+ def max_attempts
114
+ payload_object.max_attempts if payload_object.respond_to?(:max_attempts)
115
+ end
116
+
113
117
  protected
114
118
 
115
119
  def set_default_run_at
@@ -1,6 +1,8 @@
1
1
  require File.expand_path('../../../../spec/sample_jobs', __FILE__)
2
2
 
3
3
  shared_examples_for 'a delayed_job backend' do
4
+ let(:worker) { Delayed::Worker.new }
5
+
4
6
  def create_job(opts = {})
5
7
  described_class.create(opts.merge(:payload_object => SimpleJob.new))
6
8
  end
@@ -56,9 +58,11 @@ shared_examples_for 'a delayed_job backend' do
56
58
  described_class.count.should == 1
57
59
  end
58
60
 
59
- it "should be able to set priority" do
60
- @job = described_class.enqueue SimpleJob.new, 5
61
- @job.priority.should == 5
61
+ it "should be able to set priority [DEPRECATED]" do
62
+ silence_warnings do
63
+ job = described_class.enqueue SimpleJob.new, 5
64
+ job.priority.should == 5
65
+ end
62
66
  end
63
67
 
64
68
  it "should use default priority when it is not set" do
@@ -66,10 +70,12 @@ shared_examples_for 'a delayed_job backend' do
66
70
  @job.priority.should == 99
67
71
  end
68
72
 
69
- it "should be able to set run_at" do
70
- later = described_class.db_time_now + 5.minutes
71
- @job = described_class.enqueue SimpleJob.new, 5, later
72
- @job.run_at.should be_within(1).of(later)
73
+ it "should be able to set run_at [DEPRECATED]" do
74
+ silence_warnings do
75
+ later = described_class.db_time_now + 5.minutes
76
+ @job = described_class.enqueue SimpleJob.new, 5, later
77
+ @job.run_at.should be_within(1).of(later)
78
+ end
73
79
  end
74
80
 
75
81
  it "should work with jobs in modules" do
@@ -137,58 +143,39 @@ shared_examples_for 'a delayed_job backend' do
137
143
  describe "reserve" do
138
144
  before do
139
145
  Delayed::Worker.max_run_time = 2.minutes
140
- @worker = Delayed::Worker.new(:quiet => true)
141
146
  end
142
147
 
143
148
  it "should not reserve failed jobs" do
144
149
  create_job :attempts => 50, :failed_at => described_class.db_time_now
145
- described_class.reserve(@worker).should be_nil
150
+ described_class.reserve(worker).should be_nil
146
151
  end
147
152
 
148
153
  it "should not reserve jobs scheduled for the future" do
149
- create_job :run_at => (described_class.db_time_now + 1.minute)
150
- described_class.reserve(@worker).should be_nil
154
+ create_job :run_at => described_class.db_time_now + 1.minute
155
+ described_class.reserve(worker).should be_nil
151
156
  end
152
157
 
153
- it "should lock the job so other workers can't reserve it" do
158
+ it "should not reserve jobs locked by other workers" do
154
159
  job = create_job
155
- described_class.reserve(@worker).should == job
156
- new_worker = Delayed::Worker.new(:quiet => true)
157
- new_worker.name = 'worker2'
158
- described_class.reserve(new_worker).should be_nil
160
+ other_worker = Delayed::Worker.new
161
+ other_worker.name = 'other_worker'
162
+ described_class.reserve(other_worker).should == job
163
+ described_class.reserve(worker).should be_nil
159
164
  end
160
165
 
161
166
  it "should reserve open jobs" do
162
167
  job = create_job
163
- described_class.reserve(@worker).should == job
168
+ described_class.reserve(worker).should == job
164
169
  end
165
170
 
166
171
  it "should reserve expired jobs" do
167
- job = create_job(:locked_by => @worker.name, :locked_at => described_class.db_time_now - 3.minutes)
168
- described_class.reserve(@worker).should == job
172
+ job = create_job(:locked_by => worker.name, :locked_at => described_class.db_time_now - 3.minutes)
173
+ described_class.reserve(worker).should == job
169
174
  end
170
175
 
171
176
  it "should reserve own jobs" do
172
- job = create_job(:locked_by => @worker.name, :locked_at => (described_class.db_time_now - 1.minutes))
173
- described_class.reserve(@worker).should == job
174
- end
175
- end
176
-
177
- context "when another worker has worked on a task since the job was found to be available, it" do
178
-
179
- before :each do
180
- @job = described_class.create :payload_object => SimpleJob.new
181
- @job_copy_for_worker_2 = described_class.find(@job.id)
182
- end
183
-
184
- it "should not allow a second worker to get exclusive access if already successfully processed by worker1" do
185
- @job.destroy
186
- @job_copy_for_worker_2.lock_exclusively!(4.hours, 'worker2').should == false
187
- end
188
-
189
- 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
190
- @job.update_attributes(:attempts => 1, :run_at => described_class.db_time_now + 1.day)
191
- @job_copy_for_worker_2.lock_exclusively!(4.hours, 'worker2').should == false
177
+ job = create_job(:locked_by => worker.name, :locked_at => (described_class.db_time_now - 1.minutes))
178
+ described_class.reserve(worker).should == job
192
179
  end
193
180
  end
194
181
 
@@ -222,8 +209,9 @@ shared_examples_for 'a delayed_job backend' do
222
209
  end
223
210
 
224
211
  it "should fetch jobs ordered by priority" do
225
- 10.times { described_class.enqueue SimpleJob.new, rand(10) }
226
- jobs = described_class.find_available('worker', 10)
212
+ 10.times { described_class.enqueue SimpleJob.new, :priority => rand(10) }
213
+ jobs = []
214
+ 10.times { jobs << described_class.reserve(worker) }
227
215
  jobs.size.should == 10
228
216
  jobs.each_cons(2) do |a, b|
229
217
  a.priority.should <= b.priority
@@ -233,33 +221,31 @@ shared_examples_for 'a delayed_job backend' do
233
221
  it "should only find jobs greater than or equal to min priority" do
234
222
  min = 5
235
223
  Delayed::Worker.min_priority = min
236
- 10.times {|i| described_class.enqueue SimpleJob.new, i }
237
- jobs = described_class.find_available('worker', 10)
238
- jobs.each {|job| job.priority.should >= min}
224
+ 10.times {|i| described_class.enqueue SimpleJob.new, :priority => i }
225
+ 5.times { described_class.reserve(worker).priority.should >= min }
239
226
  end
240
227
 
241
228
  it "should only find jobs less than or equal to max priority" do
242
229
  max = 5
243
230
  Delayed::Worker.max_priority = max
244
- 10.times {|i| described_class.enqueue SimpleJob.new, i }
245
- jobs = described_class.find_available('worker', 10)
246
- jobs.each {|job| job.priority.should <= max}
231
+ 10.times {|i| described_class.enqueue SimpleJob.new, :priority => i }
232
+ 5.times { described_class.reserve(worker).priority.should <= max }
247
233
  end
248
234
  end
249
235
 
250
236
  context "clear_locks!" do
251
237
  before do
252
- @job = create_job(:locked_by => 'worker', :locked_at => described_class.db_time_now)
238
+ @job = create_job(:locked_by => 'worker1', :locked_at => described_class.db_time_now)
253
239
  end
254
240
 
255
241
  it "should clear locks for the given worker" do
256
- described_class.clear_locks!('worker')
257
- described_class.find_available('worker2', 5, 1.minute).should include(@job)
242
+ described_class.clear_locks!('worker1')
243
+ described_class.reserve(worker).should == @job
258
244
  end
259
245
 
260
246
  it "should not clear locks for other workers" do
261
- described_class.clear_locks!('worker1')
262
- described_class.find_available('worker1', 5, 1.minute).should_not include(@job)
247
+ described_class.clear_locks!('different_worker')
248
+ described_class.reserve(worker).should_not == @job
263
249
  end
264
250
  end
265
251
 
@@ -285,6 +271,21 @@ shared_examples_for 'a delayed_job backend' do
285
271
  @job.id.should_not be_nil
286
272
  end
287
273
  end
274
+
275
+ context "max_attempts" do
276
+ before(:each) do
277
+ @job = described_class.enqueue SimpleJob.new
278
+ end
279
+
280
+ it 'should not be defined' do
281
+ @job.max_attempts.should be_nil
282
+ end
283
+
284
+ it 'should use the max_retries value on the payload when defined' do
285
+ @job.payload_object.stub!(:max_attempts).and_return(99)
286
+ @job.max_attempts.should == 99
287
+ end
288
+ end
288
289
 
289
290
  describe "yaml serialization" do
290
291
  it "should reload changed attributes" do
@@ -307,9 +308,6 @@ shared_examples_for 'a delayed_job backend' do
307
308
  describe "worker integration" do
308
309
  before do
309
310
  Delayed::Job.delete_all
310
-
311
- @worker = Delayed::Worker.new(:max_priority => nil, :min_priority => nil, :quiet => true)
312
-
313
311
  SimpleJob.runs = 0
314
312
  end
315
313
 
@@ -319,7 +317,7 @@ shared_examples_for 'a delayed_job backend' do
319
317
  old_max_run_time = Delayed::Worker.max_run_time
320
318
  Delayed::Worker.max_run_time = 1.second
321
319
  @job = Delayed::Job.create :payload_object => LongRunningJob.new
322
- @worker.run(@job)
320
+ worker.run(@job)
323
321
  @job.reload.last_error.should =~ /expired/
324
322
  @job.attempts.should == 1
325
323
  ensure
@@ -331,7 +329,7 @@ shared_examples_for 'a delayed_job backend' do
331
329
  it "should mark the job as failed" do
332
330
  Delayed::Worker.destroy_failed_jobs = false
333
331
  job = described_class.create! :handler => "--- !ruby/object:JobThatDoesNotExist {}"
334
- @worker.work_off
332
+ worker.work_off
335
333
  job.reload
336
334
  job.failed_at.should_not be_nil
337
335
  end
@@ -350,7 +348,7 @@ shared_examples_for 'a delayed_job backend' do
350
348
  it "should record last_error when destroy_failed_jobs = false, max_attempts = 1" do
351
349
  Delayed::Worker.destroy_failed_jobs = false
352
350
  Delayed::Worker.max_attempts = 1
353
- @worker.run(@job)
351
+ worker.run(@job)
354
352
  @job.reload
355
353
  @job.last_error.should =~ /did not work/
356
354
  @job.attempts.should == 1
@@ -358,7 +356,7 @@ shared_examples_for 'a delayed_job backend' do
358
356
  end
359
357
 
360
358
  it "should re-schedule jobs after failing" do
361
- @worker.work_off
359
+ worker.work_off
362
360
  @job.reload
363
361
  @job.last_error.should =~ /did not work/
364
362
  @job.last_error.should =~ /sample_jobs.rb:\d+:in `perform'/
@@ -371,7 +369,7 @@ shared_examples_for 'a delayed_job backend' do
371
369
 
372
370
  it 'should re-schedule with handler provided time if present' do
373
371
  @job = Delayed::Job.enqueue(CustomRescheduleJob.new(99.minutes))
374
- @worker.run(@job)
372
+ worker.run(@job)
375
373
  @job.reload
376
374
 
377
375
  (Delayed::Job.db_time_now + 99.minutes - @job.run_at).abs.should < 1
@@ -381,7 +379,7 @@ shared_examples_for 'a delayed_job backend' do
381
379
  error_with_nil_message = StandardError.new
382
380
  error_with_nil_message.stub!(:message).and_return nil
383
381
  @job.stub!(:invoke_job).and_raise error_with_nil_message
384
- lambda{@worker.run(@job)}.should_not raise_error
382
+ lambda{worker.run(@job)}.should_not raise_error
385
383
  end
386
384
  end
387
385
 
@@ -399,7 +397,7 @@ shared_examples_for 'a delayed_job backend' do
399
397
 
400
398
  it "should run that hook" do
401
399
  @job.payload_object.should_receive :failure
402
- Delayed::Worker.max_attempts.times { @worker.reschedule(@job) }
400
+ worker.reschedule(@job)
403
401
  end
404
402
  end
405
403
 
@@ -422,7 +420,7 @@ shared_examples_for 'a delayed_job backend' do
422
420
 
423
421
  it "should not try to run that hook" do
424
422
  lambda do
425
- Delayed::Worker.max_attempts.times { @worker.reschedule(@job) }
423
+ Delayed::Worker.max_attempts.times { worker.reschedule(@job) }
426
424
  end.should_not raise_exception(NoMethodError)
427
425
  end
428
426
  end
@@ -437,12 +435,12 @@ shared_examples_for 'a delayed_job backend' do
437
435
 
438
436
  it "should be destroyed if it failed more than Worker.max_attempts times" do
439
437
  @job.should_receive(:destroy)
440
- Delayed::Worker.max_attempts.times { @worker.reschedule(@job) }
438
+ Delayed::Worker.max_attempts.times { worker.reschedule(@job) }
441
439
  end
442
440
 
443
441
  it "should not be destroyed if failed fewer than Worker.max_attempts times" do
444
442
  @job.should_not_receive(:destroy)
445
- (Delayed::Worker.max_attempts - 1).times { @worker.reschedule(@job) }
443
+ (Delayed::Worker.max_attempts - 1).times { worker.reschedule(@job) }
446
444
  end
447
445
  end
448
446
 
@@ -455,12 +453,12 @@ shared_examples_for 'a delayed_job backend' do
455
453
 
456
454
  it "should be failed if it failed more than Worker.max_attempts times" do
457
455
  @job.reload.failed_at.should == nil
458
- Delayed::Worker.max_attempts.times { @worker.reschedule(@job) }
456
+ Delayed::Worker.max_attempts.times { worker.reschedule(@job) }
459
457
  @job.reload.failed_at.should_not == nil
460
458
  end
461
459
 
462
460
  it "should not be failed if it failed fewer than Worker.max_attempts times" do
463
- (Delayed::Worker.max_attempts - 1).times { @worker.reschedule(@job) }
461
+ (Delayed::Worker.max_attempts - 1).times { worker.reschedule(@job) }
464
462
  @job.reload.failed_at.should == nil
465
463
  end
466
464
  end
@@ -1,4 +1,4 @@
1
- require 'action_mailer'
1
+ require 'mail'
2
2
 
3
3
  module Delayed
4
4
  class PerformableMailer < PerformableMethod
@@ -6,11 +6,11 @@ module Delayed
6
6
  object.send(method_name, *args).deliver
7
7
  end
8
8
  end
9
- end
10
9
 
11
- ActionMailer::Base.class_eval do
12
- def self.delay(options = {})
13
- Delayed::DelayProxy.new(Delayed::PerformableMailer, self, options)
10
+ module DelayMail
11
+ def delay(options = {})
12
+ DelayProxy.new(PerformableMailer, self, options)
13
+ end
14
14
  end
15
15
  end
16
16
 
@@ -18,4 +18,4 @@ Mail::Message.class_eval do
18
18
  def delay(*args)
19
19
  raise RuntimeError, "Use MyMailer.delay.mailer_action(args) to delay sending of emails."
20
20
  end
21
- end
21
+ end
@@ -5,6 +5,10 @@ module Delayed
5
5
  class Railtie < Rails::Railtie
6
6
  initializer :after_initialize do
7
7
  Delayed::Worker.guess_backend
8
+
9
+ ActiveSupport.on_load(:action_mailer) do
10
+ ActionMailer::Base.send(:extend, Delayed::DelayMail)
11
+ end
8
12
  end
9
13
 
10
14
  rake_tasks do
@@ -6,6 +6,17 @@
6
6
  # after "deploy:stop", "delayed_job:stop"
7
7
  # after "deploy:start", "delayed_job:start"
8
8
  # after "deploy:restart", "delayed_job:restart"
9
+ #
10
+ # If you want to use command line options, for example to start multiple workers,
11
+ # define a Capistrano variable delayed_job_args:
12
+ #
13
+ # set :delayed_jobs_args, "-n 2"
14
+ #
15
+ # If you've got delayed_job workers running on a servers, you can also specify
16
+ # which servers have delayed_job running and should be restarted after deploy.
17
+ #
18
+ # set :delayed_job_server_role, :worker
19
+ #
9
20
 
10
21
  Capistrano::Configuration.instance.load do
11
22
  namespace :delayed_job do
@@ -17,18 +28,22 @@ Capistrano::Configuration.instance.load do
17
28
  fetch(:delayed_job_args, "")
18
29
  end
19
30
 
31
+ def roles
32
+ fetch(:delayed_job_server_role, :app)
33
+ end
34
+
20
35
  desc "Stop the delayed_job process"
21
- task :stop, :roles => :app do
36
+ task :stop, :roles => lambda { roles } do
22
37
  run "cd #{current_path};#{rails_env} script/delayed_job stop"
23
38
  end
24
39
 
25
40
  desc "Start the delayed_job process"
26
- task :start, :roles => :app do
41
+ task :start, :roles => lambda { roles } do
27
42
  run "cd #{current_path};#{rails_env} script/delayed_job start #{args}"
28
43
  end
29
44
 
30
45
  desc "Restart the delayed_job process"
31
- task :restart, :roles => :app do
46
+ task :restart, :roles => lambda { roles } do
32
47
  run "cd #{current_path};#{rails_env} script/delayed_job restart #{args}"
33
48
  end
34
49
  end
@@ -6,6 +6,6 @@ namespace :jobs do
6
6
 
7
7
  desc "Start a delayed_job worker."
8
8
  task :work => :environment do
9
- Delayed::Worker.new(:min_priority => ENV['MIN_PRIORITY'], :max_priority => ENV['MAX_PRIORITY']).start
9
+ Delayed::Worker.new(:min_priority => ENV['MIN_PRIORITY'], :max_priority => ENV['MAX_PRIORITY'], :quiet => false).start
10
10
  end
11
11
  end
@@ -132,7 +132,7 @@ module Delayed
132
132
  # Reschedule the job in the future (when a job fails).
133
133
  # Uses an exponential scale depending on the number of failed attempts.
134
134
  def reschedule(job, time = nil)
135
- if (job.attempts += 1) < self.class.max_attempts
135
+ if (job.attempts += 1) < max_attempts(job)
136
136
  time ||= job.reschedule_at
137
137
  job.run_at = time
138
138
  job.unlock
@@ -157,6 +157,10 @@ module Delayed
157
157
  logger.add level, "#{Time.now.strftime('%FT%T%z')}: #{text}" if logger
158
158
  end
159
159
 
160
+ def max_attempts(job)
161
+ job.max_attempts || self.class.max_attempts
162
+ end
163
+
160
164
  protected
161
165
 
162
166
  def handle_failed_job(job, error)
@@ -13,6 +13,7 @@ class CreateDelayedJobs < ActiveRecord::Migration
13
13
  end
14
14
 
15
15
  add_index :delayed_jobs, [:priority, :run_at], :name => 'delayed_jobs_priority'
16
+ add_index :delayed_jobs, :locked_by, :name => 'delayed_jobs_locked_by'
16
17
  end
17
18
 
18
19
  def self.down
@@ -25,8 +25,8 @@ class LongRunningJob
25
25
  end
26
26
 
27
27
  class OnPermanentFailureJob < SimpleJob
28
- def failure
29
- end
28
+ def failure; end
29
+ def max_attempts; 1; end
30
30
  end
31
31
 
32
32
  module M
@@ -5,6 +5,7 @@ require 'bundler/setup'
5
5
  require 'rspec'
6
6
  require 'logger'
7
7
 
8
+ require 'rails'
8
9
  require 'active_record'
9
10
  require 'action_mailer'
10
11
 
@@ -13,7 +14,6 @@ require 'delayed/backend/shared_spec'
13
14
 
14
15
  Delayed::Worker.logger = Logger.new('/tmp/dj.log')
15
16
  ENV['RAILS_ENV'] = 'test'
16
- require 'rails'
17
17
 
18
18
  config = YAML.load(File.read('spec/database.yml'))
19
19
  ActiveRecord::Base.configurations = {'test' => config['mysql']}
@@ -53,3 +53,6 @@ Delayed::Worker.backend = :active_record
53
53
 
54
54
  # Add this directory so the ActiveSupport autoloading works
55
55
  ActiveSupport::Dependencies.autoload_paths << File.dirname(__FILE__)
56
+
57
+ # Add this to simulate Railtie initializer being executed
58
+ ActionMailer::Base.send(:extend, Delayed::DelayMail)
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: delayed_job
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 15
4
5
  prerelease: false
5
6
  segments:
6
7
  - 2
7
8
  - 1
8
- - 1
9
- version: 2.1.1
9
+ - 2
10
+ version: 2.1.2
10
11
  platform: ruby
11
12
  authors:
12
13
  - Brandon Keepers
@@ -15,16 +16,18 @@ autorequire:
15
16
  bindir: bin
16
17
  cert_chain: []
17
18
 
18
- date: 2010-11-14 00:00:00 -06:00
19
+ date: 2010-12-01 00:00:00 -05:00
19
20
  default_executable:
20
21
  dependencies:
21
22
  - !ruby/object:Gem::Dependency
22
23
  name: daemons
23
24
  prerelease: false
24
25
  requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
25
27
  requirements:
26
28
  - - ">="
27
29
  - !ruby/object:Gem::Version
30
+ hash: 3
28
31
  segments:
29
32
  - 0
30
33
  version: "0"
@@ -34,9 +37,11 @@ dependencies:
34
37
  name: activesupport
35
38
  prerelease: false
36
39
  requirement: &id002 !ruby/object:Gem::Requirement
40
+ none: false
37
41
  requirements:
38
42
  - - ~>
39
43
  - !ruby/object:Gem::Version
44
+ hash: 7
40
45
  segments:
41
46
  - 3
42
47
  - 0
@@ -47,9 +52,11 @@ dependencies:
47
52
  name: rspec
48
53
  prerelease: false
49
54
  requirement: &id003 !ruby/object:Gem::Requirement
55
+ none: false
50
56
  requirements:
51
57
  - - ~>
52
58
  - !ruby/object:Gem::Version
59
+ hash: 3
53
60
  segments:
54
61
  - 2
55
62
  - 0
@@ -60,9 +67,11 @@ dependencies:
60
67
  name: rake
61
68
  prerelease: false
62
69
  requirement: &id004 !ruby/object:Gem::Requirement
70
+ none: false
63
71
  requirements:
64
72
  - - ">="
65
73
  - !ruby/object:Gem::Version
74
+ hash: 3
66
75
  segments:
67
76
  - 0
68
77
  version: "0"
@@ -72,9 +81,11 @@ dependencies:
72
81
  name: rails
73
82
  prerelease: false
74
83
  requirement: &id005 !ruby/object:Gem::Requirement
84
+ none: false
75
85
  requirements:
76
86
  - - ~>
77
87
  - !ruby/object:Gem::Version
88
+ hash: 7
78
89
  segments:
79
90
  - 3
80
91
  - 0
@@ -85,38 +96,30 @@ dependencies:
85
96
  name: sqlite3-ruby
86
97
  prerelease: false
87
98
  requirement: &id006 !ruby/object:Gem::Requirement
99
+ none: false
88
100
  requirements:
89
101
  - - ">="
90
102
  - !ruby/object:Gem::Version
103
+ hash: 3
91
104
  segments:
92
105
  - 0
93
106
  version: "0"
94
107
  type: :development
95
108
  version_requirements: *id006
96
109
  - !ruby/object:Gem::Dependency
97
- name: ruby-debug
110
+ name: mysql
98
111
  prerelease: false
99
112
  requirement: &id007 !ruby/object:Gem::Requirement
113
+ none: false
100
114
  requirements:
101
115
  - - ">="
102
116
  - !ruby/object:Gem::Version
117
+ hash: 3
103
118
  segments:
104
119
  - 0
105
120
  version: "0"
106
121
  type: :development
107
122
  version_requirements: *id007
108
- - !ruby/object:Gem::Dependency
109
- name: mysql
110
- prerelease: false
111
- requirement: &id008 !ruby/object:Gem::Requirement
112
- requirements:
113
- - - ">="
114
- - !ruby/object:Gem::Version
115
- segments:
116
- - 0
117
- version: "0"
118
- type: :development
119
- version_requirements: *id008
120
123
  description: |-
121
124
  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.
122
125
 
@@ -176,23 +179,27 @@ rdoc_options:
176
179
  require_paths:
177
180
  - lib
178
181
  required_ruby_version: !ruby/object:Gem::Requirement
182
+ none: false
179
183
  requirements:
180
184
  - - ">="
181
185
  - !ruby/object:Gem::Version
186
+ hash: 3
182
187
  segments:
183
188
  - 0
184
189
  version: "0"
185
190
  required_rubygems_version: !ruby/object:Gem::Requirement
191
+ none: false
186
192
  requirements:
187
193
  - - ">="
188
194
  - !ruby/object:Gem::Version
195
+ hash: 3
189
196
  segments:
190
197
  - 0
191
198
  version: "0"
192
199
  requirements: []
193
200
 
194
201
  rubyforge_project:
195
- rubygems_version: 1.3.6
202
+ rubygems_version: 1.3.7
196
203
  signing_key:
197
204
  specification_version: 3
198
205
  summary: Database-backed asynchronous priority queue system -- Extracted from Shopify