delayed_job 4.0.0.beta2 → 4.0.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.
data/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ 4.0.0 - 2013-07-30
2
+ ==================
3
+ * Rails 4 compatibility
4
+ * Reverted threaded startup due to daemons incompatibilities
5
+ * Attempt to recover from job reservation errors
6
+
1
7
  4.0.0.beta2 - 2013-05-28
2
8
  ========================
3
9
  * Rails 4 compatibility
data/CONTRIBUTING.md CHANGED
@@ -7,7 +7,16 @@ If you find what looks like a bug:
7
7
  if anyone else had the same issue.
8
8
  * Check the "GitHub issue tracker":http://github.com/collectiveidea/delayed_job/issues/
9
9
  to see if anyone else has reported issue.
10
- * If you don't see anything, create an issue with information on how to reproduce it.
10
+ * Make sure you are using the latest version of delayed_job
11
+ ![Gem Version](https://badge.fury.io/rb/delayed_job.png)
12
+ * Make sure you are using the latest backend gem for delayed_job
13
+ * Active Record ![Gem Version](https://badge.fury.io/rb/delayed_job_active_record.png)
14
+ * Mongoid ![Gem Version](https://badge.fury.io/rb/delayed_job_mongoid.png)
15
+ * If you are still having an issue, create an issue including:
16
+ * Ruby version
17
+ * Gemfile.lock contents or at least major gem versions, such as Rails version
18
+ * Steps to reproduce the issue
19
+ * Full backtrace for any errors encountered
11
20
 
12
21
  If you want to contribute an enhancement or a fix:
13
22
 
data/README.md CHANGED
@@ -316,6 +316,8 @@ By default all jobs are scheduled with priority = 0, which is top priority. You
316
316
 
317
317
  The default behavior is to read 5 jobs from the queue when finding an available job. You can configure this by setting Delayed::Worker.read_ahead.
318
318
 
319
+ By default all jobs will be queued without a named queue. A default named queue can be specified by using Delayed::Worker.default_queue_name.
320
+
319
321
  It is possible to disable delayed jobs for testing purposes. Set Delayed::Worker.delay_jobs = false to execute all jobs realtime.
320
322
 
321
323
  Here is an example of changing job parameters in Rails:
@@ -327,6 +329,7 @@ Delayed::Worker.sleep_delay = 60
327
329
  Delayed::Worker.max_attempts = 3
328
330
  Delayed::Worker.max_run_time = 5.minutes
329
331
  Delayed::Worker.read_ahead = 10
332
+ Delayed::Worker.default_queue_name = 'default'
330
333
  Delayed::Worker.delay_jobs = !Rails.env.test?
331
334
  ```
332
335
 
data/delayed_job.gemspec CHANGED
@@ -13,5 +13,5 @@ Gem::Specification.new do |spec|
13
13
  spec.require_paths = ['lib']
14
14
  spec.summary = 'Database-backed asynchronous priority queue system -- Extracted from Shopify'
15
15
  spec.test_files = Dir.glob('spec/**/*')
16
- spec.version = '4.0.0.beta2'
16
+ spec.version = '4.0.0'
17
17
  end
@@ -47,6 +47,10 @@ module Delayed
47
47
  end
48
48
  end
49
49
 
50
+ # Allow the backend to attempt recovery from reserve errors
51
+ def recover_from(error)
52
+ end
53
+
50
54
  # Hook method that is called before a new worker is forked
51
55
  def before_fork
52
56
  end
@@ -82,7 +86,13 @@ module Delayed
82
86
  end
83
87
 
84
88
  def payload_object
85
- @payload_object ||= YAML.load(self.handler)
89
+ if YAML.respond_to?(:unsafe_load)
90
+ #See https://github.com/dtao/safe_yaml
91
+ #When the method is there, we need to load our YAML like this...
92
+ @payload_object ||= YAML.load(self.handler, :safe => false)
93
+ else
94
+ @payload_object ||= YAML.load(self.handler)
95
+ end
86
96
  rescue TypeError, LoadError, NameError, ArgumentError => e
87
97
  raise DeserializationError,
88
98
  "Job failed to load: #{e.message}. Handler: #{handler.inspect}"
@@ -399,7 +399,7 @@ shared_examples_for "a delayed_job backend" do
399
399
  end
400
400
 
401
401
  it "uses the max_retries value on the payload when defined" do
402
- @job.payload_object.stub!(:max_attempts).and_return(99)
402
+ @job.payload_object.stub(:max_attempts).and_return(99)
403
403
  expect(@job.max_attempts).to eq(99)
404
404
  end
405
405
  end
@@ -504,8 +504,8 @@ shared_examples_for "a delayed_job backend" do
504
504
 
505
505
  it "does not fail when the triggered error doesn't have a message" do
506
506
  error_with_nil_message = StandardError.new
507
- error_with_nil_message.stub!(:message).and_return nil
508
- @job.stub!(:invoke_job).and_raise error_with_nil_message
507
+ error_with_nil_message.stub(:message).and_return nil
508
+ @job.stub(:invoke_job).and_raise error_with_nil_message
509
509
  expect{worker.run(@job)}.not_to raise_error
510
510
  end
511
511
  end
@@ -548,7 +548,7 @@ shared_examples_for "a delayed_job backend" do
548
548
  it "does not try to run that hook" do
549
549
  expect {
550
550
  Delayed::Worker.max_attempts.times { worker.reschedule(@job) }
551
- }.not_to raise_exception(NoMethodError)
551
+ }.not_to raise_exception
552
552
  end
553
553
  end
554
554
  end
@@ -78,14 +78,10 @@ module Delayed
78
78
  process_name = "delayed_job.#{@options[:identifier]}"
79
79
  run_process(process_name, dir)
80
80
  else
81
- threads = []
82
81
  worker_count.times do |worker_index|
83
- threads << Thread.start do
84
- process_name = worker_count == 1 ? "delayed_job" : "delayed_job.#{worker_index}"
85
- run_process(process_name, dir)
86
- end
82
+ process_name = worker_count == 1 ? "delayed_job" : "delayed_job.#{worker_index}"
83
+ run_process(process_name, dir)
87
84
  end
88
- threads.each(&:join)
89
85
  end
90
86
  end
91
87
 
@@ -107,6 +107,7 @@ module Delayed
107
107
 
108
108
  def initialize(options={})
109
109
  @quiet = options.has_key?(:quiet) ? options[:quiet] : true
110
+ @failed_reserve_count = 0
110
111
 
111
112
  [:min_priority, :max_priority, :sleep_delay, :read_ahead, :queues, :exit_on_complete].each do |option|
112
113
  self.class.send("#{option}=", options[option]) if options.has_key?(option)
@@ -262,9 +263,21 @@ module Delayed
262
263
  # Run the next job we can get an exclusive lock on.
263
264
  # If no jobs are left we return nil
264
265
  def reserve_and_run_one_job
265
- job = Delayed::Job.reserve(self)
266
+ job = reserve_job
266
267
  self.class.lifecycle.run_callbacks(:perform, self, job){ run(job) } if job
267
268
  end
269
+
270
+ def reserve_job
271
+ job = Delayed::Job.reserve(self)
272
+ @failed_reserve_count = 0
273
+ job
274
+ rescue Exception => error
275
+ say "Error while reserving job: #{error}"
276
+ Delayed::Job.recover_from(error)
277
+ @failed_reserve_count += 1
278
+ raise FatalBackendError if @failed_reserve_count >= 10
279
+ nil
280
+ end
268
281
  end
269
282
 
270
283
  end
@@ -4,7 +4,7 @@ describe Delayed::Lifecycle do
4
4
  let(:lifecycle) { Delayed::Lifecycle.new }
5
5
  let(:callback) { lambda {|*args|} }
6
6
  let(:arguments) { [1] }
7
- let(:behavior) { mock(Object, :before! => nil, :after! => nil, :inside! => nil) }
7
+ let(:behavior) { double(Object, :before! => nil, :after! => nil, :inside! => nil) }
8
8
  let(:wrapped_block) { Proc.new { behavior.inside! } }
9
9
 
10
10
  describe "before callbacks" do
@@ -30,8 +30,8 @@ describe ActionMailer::Base do
30
30
  describe Delayed::PerformableMailer do
31
31
  describe "perform" do
32
32
  it "calls the method and #deliver on the mailer" do
33
- email = mock('email', :deliver => true)
34
- mailer_class = mock('MailerClass', :signup => email)
33
+ email = double('email', :deliver => true)
34
+ mailer_class = double('MailerClass', :signup => email)
35
35
  mailer = Delayed::PerformableMailer.new(mailer_class, :signup, ['john@example.com'])
36
36
 
37
37
  mailer_class.should_receive(:signup).with('john@example.com')
@@ -36,7 +36,7 @@ describe Delayed::PerformableMethod do
36
36
  end
37
37
  expect {
38
38
  Delayed::PerformableMethod.new(clazz.new, :private_method, [])
39
- }.not_to raise_error(NoMethodError)
39
+ }.not_to raise_error
40
40
  end
41
41
 
42
42
  describe "hooks" do
data/spec/worker_spec.rb CHANGED
@@ -24,7 +24,7 @@ describe Delayed::Worker do
24
24
  describe "job_say" do
25
25
  before do
26
26
  @worker = Delayed::Worker.new
27
- @job = stub('job', :id => 123, :name => 'ExampleJob')
27
+ @job = double('job', :id => 123, :name => 'ExampleJob')
28
28
  end
29
29
 
30
30
  it "logs with job name and id" do
@@ -71,4 +71,32 @@ describe Delayed::Worker do
71
71
  end
72
72
  end
73
73
  end
74
+
75
+ context "worker job reservation" do
76
+ before do
77
+ Delayed::Worker.exit_on_complete = true
78
+ end
79
+
80
+ after do
81
+ Delayed::Worker.exit_on_complete = false
82
+ end
83
+
84
+ it "handles error during job reservation" do
85
+ Delayed::Job.should_receive(:reserve).and_raise(Exception)
86
+ Delayed::Worker.new.work_off
87
+ end
88
+
89
+ it "gives up after 10 backend failures" do
90
+ Delayed::Job.stub(:reserve).and_raise(Exception)
91
+ worker = Delayed::Worker.new
92
+ 9.times { worker.work_off }
93
+ expect(lambda { worker.work_off }).to raise_exception
94
+ end
95
+
96
+ it "allows the backend to attempt recovery from reservation errors" do
97
+ Delayed::Job.should_receive(:reserve).and_raise(Exception)
98
+ Delayed::Job.should_receive(:recover_from).with(instance_of(Exception))
99
+ Delayed::Worker.new.work_off
100
+ end
101
+ end
74
102
  end
metadata CHANGED
@@ -1,7 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: delayed_job
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.0.beta2
4
+ version: 4.0.0
5
+ prerelease:
5
6
  platform: ruby
6
7
  authors:
7
8
  - Brandon Keepers
@@ -15,12 +16,12 @@ authors:
15
16
  autorequire:
16
17
  bindir: bin
17
18
  cert_chain: []
18
- date: 2013-05-28 00:00:00.000000000 Z
19
+ date: 2013-07-30 00:00:00.000000000 Z
19
20
  dependencies:
20
21
  - !ruby/object:Gem::Dependency
21
- prerelease: false
22
22
  name: activesupport
23
- version_requirements: !ruby/object:Gem::Requirement
23
+ requirement: !ruby/object:Gem::Requirement
24
+ none: false
24
25
  requirements:
25
26
  - - ! '>='
26
27
  - !ruby/object:Gem::Version
@@ -28,7 +29,10 @@ dependencies:
28
29
  - - <
29
30
  - !ruby/object:Gem::Version
30
31
  version: '4.1'
31
- requirement: !ruby/object:Gem::Requirement
32
+ type: :runtime
33
+ prerelease: false
34
+ version_requirements: !ruby/object:Gem::Requirement
35
+ none: false
32
36
  requirements:
33
37
  - - ! '>='
34
38
  - !ruby/object:Gem::Version
@@ -36,7 +40,6 @@ dependencies:
36
40
  - - <
37
41
  - !ruby/object:Gem::Version
38
42
  version: '4.1'
39
- type: :runtime
40
43
  description: Delayed_job (or DJ) encapsulates the common pattern of asynchronously
41
44
  executing longer tasks in the background. It is a direct extraction from Shopify
42
45
  where the job table is responsible for a multitude of core tasks.
@@ -98,26 +101,33 @@ files:
98
101
  homepage: http://github.com/collectiveidea/delayed_job
99
102
  licenses:
100
103
  - MIT
101
- metadata: {}
102
104
  post_install_message:
103
105
  rdoc_options: []
104
106
  require_paths:
105
107
  - lib
106
108
  required_ruby_version: !ruby/object:Gem::Requirement
109
+ none: false
107
110
  requirements:
108
111
  - - ! '>='
109
112
  - !ruby/object:Gem::Version
110
113
  version: '0'
114
+ segments:
115
+ - 0
116
+ hash: 3979399263094595498
111
117
  required_rubygems_version: !ruby/object:Gem::Requirement
118
+ none: false
112
119
  requirements:
113
- - - ! '>'
120
+ - - ! '>='
114
121
  - !ruby/object:Gem::Version
115
- version: 1.3.1
122
+ version: '0'
123
+ segments:
124
+ - 0
125
+ hash: 3979399263094595498
116
126
  requirements: []
117
127
  rubyforge_project:
118
- rubygems_version: 2.0.3
128
+ rubygems_version: 1.8.23
119
129
  signing_key:
120
- specification_version: 4
130
+ specification_version: 3
121
131
  summary: Database-backed asynchronous priority queue system -- Extracted from Shopify
122
132
  test_files:
123
133
  - spec/autoloaded/clazz.rb
checksums.yaml DELETED
@@ -1,15 +0,0 @@
1
- ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- MTQxN2VkZDVhM2YxY2RhNzE0NzRiN2ZlMDE0ZmQ3Y2I3ZjM5ODkyMA==
5
- data.tar.gz: !binary |-
6
- NjI3N2EyYTkzY2E2M2YyNmE2OWYxNTVhOWZkNWI5ZGViZWEzYjIzNQ==
7
- !binary "U0hBNTEy":
8
- metadata.gz: !binary |-
9
- MjhjOGJkN2YxNGM0NzI0ZDIxOTE0ZGVjNTk0OGZhZWQxZmY4YTkxYTczNWRk
10
- ZWIxNTEzYWE4Mzc4OGE0Mjc2NzhhMDQ0NjdiZGVjMDc1YzEyMDUyOTFmYmRl
11
- OTdmNzYyZDQ4YzJjZWVlOGUzNjczY2VlOTczYTc5Mjk1ZjhjZTE=
12
- data.tar.gz: !binary |-
13
- MDcxN2FkZDMxYWVhOTI2NjBmN2FmNzgyN2I0MTZkMmM3YmNjZWM4NTk2MzVl
14
- ZDA2ZWQ1ZWE4YTE3OGI0ZDlmMTNjMGQ0ZDgyNTllNWM1OTczNzQxNWY3ZTFk
15
- NjFkM2ZjMGEzOGYyMTQzNjNhMjg5ODRjNGEzNTExNGM2YjJiZGE=