delayed_job 4.0.0.beta2 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
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=