delayed_job 4.0.0 → 4.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +6 -0
- data/README.md +17 -10
- data/delayed_job.gemspec +2 -2
- data/lib/delayed/backend/shared_spec.rb +49 -39
- data/lib/delayed/exceptions.rb +2 -0
- data/lib/delayed/performable_method.rb +2 -2
- data/lib/delayed/railtie.rb +1 -1
- data/lib/delayed/worker.rb +11 -4
- data/spec/helper.rb +1 -1
- data/spec/lifecycle_spec.rb +10 -10
- data/spec/performable_mailer_spec.rb +2 -2
- data/spec/performable_method_spec.rb +16 -16
- data/spec/worker_spec.rb +55 -8
- metadata +14 -24
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 44f2fddb4257788893e27e7fe18e159748132d45
|
4
|
+
data.tar.gz: ed334f09c9f6d3c9ff987a04f5131d4d8bf1286a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a43f95acb0fd7b4d1eacadc523dc470f08aa290ccf2b224819a77bd60acd8b363665bd7992372420d6d382b6ca6ead131a725f0ee638abce35405900748e2612
|
7
|
+
data.tar.gz: ff353fb2e6115237541411a67aee47381120fda1a20d56a70a0a50a51a4cc56c21e0f7e3935c1869fbcf6dbb8051199ae95e3eec68d4208f0a6c3e3f3f252cd5
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
Delayed::Job
|
2
2
|
============
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/delayed_job.png)][gem]
|
4
|
-
[![Build Status](https://
|
4
|
+
[![Build Status](https://travis-ci.org/collectiveidea/delayed_job.png?branch=master)][travis]
|
5
5
|
[![Dependency Status](https://gemnasium.com/collectiveidea/delayed_job.png?travis)][gemnasium]
|
6
6
|
[![Code Climate](https://codeclimate.com/github/collectiveidea/delayed_job.png)][codeclimate]
|
7
7
|
[![Coverage Status](https://coveralls.io/repos/collectiveidea/delayed_job/badge.png?branch=master)][coveralls]
|
8
8
|
|
9
9
|
[gem]: https://rubygems.org/gems/delayed_job
|
10
|
-
[travis]:
|
10
|
+
[travis]: https://travis-ci.org/collectiveidea/delayed_job
|
11
11
|
[gemnasium]: https://gemnasium.com/collectiveidea/delayed_job
|
12
12
|
[codeclimate]: https://codeclimate.com/github/collectiveidea/delayed_job
|
13
13
|
[coveralls]: https://coveralls.io/r/collectiveidea/delayed_job
|
@@ -36,7 +36,7 @@ delayed_job 3.0.0 only supports Rails 3.0+. See the [2.0
|
|
36
36
|
branch](https://github.com/collectiveidea/delayed_job/tree/v2.0) for Rails 2.
|
37
37
|
|
38
38
|
delayed_job supports multiple backends for storing the job queue. [See the wiki
|
39
|
-
for other backends](
|
39
|
+
for other backends](https://github.com/collectiveidea/delayed_job/wiki/Backends).
|
40
40
|
|
41
41
|
If you plan to use delayed_job with Active Record, add `delayed_job_active_record` to your `Gemfile`.
|
42
42
|
|
@@ -58,6 +58,10 @@ running the following command:
|
|
58
58
|
rails generate delayed_job:active_record
|
59
59
|
rake db:migrate
|
60
60
|
|
61
|
+
Rails 4
|
62
|
+
=======
|
63
|
+
If you are using the protected_attributes gem, it must appear before delayed_job in your gemfile.
|
64
|
+
|
61
65
|
Upgrading from 2.x to 3.0.0 on Active Record
|
62
66
|
============================================
|
63
67
|
Delayed Job 3.0.0 introduces a new column to the delayed_jobs table.
|
@@ -141,6 +145,9 @@ Notifier.signup(@user).deliver
|
|
141
145
|
|
142
146
|
# with delayed_job
|
143
147
|
Notifier.delay.signup(@user)
|
148
|
+
|
149
|
+
# with delayed_job running at a specific time
|
150
|
+
Notifier.delay(run_at: 5.minutes.from_now).signup(@user)
|
144
151
|
```
|
145
152
|
|
146
153
|
Remove the `.deliver` method to make it work. It's not ideal, but it's the best
|
@@ -183,7 +190,7 @@ You can then do the following:
|
|
183
190
|
RAILS_ENV=production script/delayed_job --queue=tracking start
|
184
191
|
RAILS_ENV=production script/delayed_job --queues=mailers,tasks start
|
185
192
|
|
186
|
-
# Runs all available jobs and
|
193
|
+
# Runs all available jobs and then exits
|
187
194
|
RAILS_ENV=production script/delayed_job start --exit-on-complete
|
188
195
|
# or to run in the foreground
|
189
196
|
RAILS_ENV=production script/delayed_job run --exit-on-complete
|
@@ -203,7 +210,7 @@ Work off queues by setting the `QUEUE` or `QUEUES` environment variable.
|
|
203
210
|
|
204
211
|
QUEUE=tracking rake jobs:work
|
205
212
|
QUEUES=mailers,tasks rake jobs:work
|
206
|
-
|
213
|
+
|
207
214
|
Restarting delayed_job
|
208
215
|
======================
|
209
216
|
|
@@ -214,7 +221,7 @@ The following syntax will restart delayed jobs:
|
|
214
221
|
To restart multiple delayed_job workers:
|
215
222
|
|
216
223
|
RAILS_ENV=production script/delayed_job -n2 restart
|
217
|
-
|
224
|
+
|
218
225
|
**Rails 4:** *replace script/delayed_job with bin/delayed_job*
|
219
226
|
|
220
227
|
|
@@ -224,7 +231,7 @@ Custom Jobs
|
|
224
231
|
Jobs are simple ruby objects with a method called perform. Any object which responds to perform can be stuffed into the jobs table. Job objects are serialized to yaml so that they can later be resurrected by the job runner.
|
225
232
|
|
226
233
|
```ruby
|
227
|
-
|
234
|
+
NewsletterJob = Struct.new(:text, :emails) do
|
228
235
|
def perform
|
229
236
|
emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
|
230
237
|
end
|
@@ -234,11 +241,11 @@ Delayed::Job.enqueue NewsletterJob.new('lorem ipsum...', Customers.find(:all).co
|
|
234
241
|
```
|
235
242
|
To set a per-job max attempts that overrides the Delayed::Worker.max_attempts you can define a max_attempts method on the job
|
236
243
|
```ruby
|
237
|
-
|
244
|
+
NewsletterJob = Struct.new(:text, :emails) do
|
238
245
|
def perform
|
239
246
|
emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
|
240
247
|
end
|
241
|
-
|
248
|
+
|
242
249
|
def max_attempts
|
243
250
|
return 3
|
244
251
|
end
|
@@ -276,7 +283,7 @@ class ParanoidNewsletterJob < NewsletterJob
|
|
276
283
|
Airbrake.notify(exception)
|
277
284
|
end
|
278
285
|
|
279
|
-
def failure
|
286
|
+
def failure(job)
|
280
287
|
page_sysadmin_in_the_middle_of_the_night
|
281
288
|
end
|
282
289
|
end
|
data/delayed_job.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
3
|
Gem::Specification.new do |spec|
|
4
|
-
spec.add_dependency 'activesupport', ['>= 3.0', '< 4.
|
4
|
+
spec.add_dependency 'activesupport', ['>= 3.0', '< 4.2']
|
5
5
|
spec.authors = ["Brandon Keepers", "Brian Ryckbost", "Chris Gaffney", "David Genord II", "Erik Michaels-Ober", "Matt Griffin", "Steve Richert", "Tobias Lütke"]
|
6
6
|
spec.description = "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."
|
7
7
|
spec.email = ['brian@collectiveidea.com']
|
@@ -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.
|
16
|
+
spec.version = '4.0.1'
|
17
17
|
end
|
@@ -116,7 +116,7 @@ shared_examples_for "a delayed_job backend" do
|
|
116
116
|
|
117
117
|
it "invokes the enqueued job" do
|
118
118
|
job = SimpleJob.new
|
119
|
-
job.
|
119
|
+
expect(job).to receive(:perform)
|
120
120
|
described_class.enqueue job
|
121
121
|
end
|
122
122
|
|
@@ -134,7 +134,7 @@ shared_examples_for "a delayed_job backend" do
|
|
134
134
|
%w(before success after).each do |callback|
|
135
135
|
it "calls #{callback} with job" do
|
136
136
|
job = described_class.enqueue(CallbackJob.new)
|
137
|
-
job.payload_object.
|
137
|
+
expect(job.payload_object).to receive(callback).with(job)
|
138
138
|
job.invoke_job
|
139
139
|
end
|
140
140
|
end
|
@@ -148,7 +148,7 @@ shared_examples_for "a delayed_job backend" do
|
|
148
148
|
|
149
149
|
it "calls the after callback with an error" do
|
150
150
|
job = described_class.enqueue(CallbackJob.new)
|
151
|
-
job.payload_object.
|
151
|
+
expect(job.payload_object).to receive(:perform).and_raise(RuntimeError.new("fail"))
|
152
152
|
|
153
153
|
expect{job.invoke_job}.to raise_error
|
154
154
|
expect(CallbackJob.messages).to eq(["enqueue", "before", "error: RuntimeError", "after"])
|
@@ -156,7 +156,7 @@ shared_examples_for "a delayed_job backend" do
|
|
156
156
|
|
157
157
|
it "calls error when before raises an error" do
|
158
158
|
job = described_class.enqueue(CallbackJob.new)
|
159
|
-
job.payload_object.
|
159
|
+
expect(job.payload_object).to receive(:before).and_raise(RuntimeError.new("fail"))
|
160
160
|
expect{job.invoke_job}.to raise_error(RuntimeError)
|
161
161
|
expect(CallbackJob.messages).to eq(["enqueue", "error: RuntimeError", "after"])
|
162
162
|
end
|
@@ -175,7 +175,7 @@ shared_examples_for "a delayed_job backend" do
|
|
175
175
|
|
176
176
|
it "raises a DeserializationError when the YAML.load raises argument error" do
|
177
177
|
job = described_class.new :handler => "--- !ruby/struct:GoingToRaiseArgError {}"
|
178
|
-
YAML.
|
178
|
+
expect(YAML).to receive(:load).and_raise(ArgumentError)
|
179
179
|
expect{job.payload_object}.to raise_error(Delayed::DeserializationError)
|
180
180
|
end
|
181
181
|
end
|
@@ -399,35 +399,47 @@ 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.
|
402
|
+
expect(@job.payload_object).to receive(:max_attempts).and_return(99)
|
403
403
|
expect(@job.max_attempts).to eq(99)
|
404
404
|
end
|
405
405
|
end
|
406
406
|
|
407
407
|
describe "yaml serialization" do
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
408
|
+
context "when serializing jobs" do
|
409
|
+
it "raises error ArgumentError for new records" do
|
410
|
+
story = Story.new(:text => 'hello')
|
411
|
+
if story.respond_to?(:new_record?)
|
412
|
+
expect {
|
413
|
+
story.delay.tell
|
414
|
+
}.to raise_error(ArgumentError, 'Jobs cannot be created for non-persisted records')
|
415
|
+
end
|
416
|
+
end
|
414
417
|
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
+
it "raises error ArgumentError for destroyed records" do
|
419
|
+
story = Story.create(:text => 'hello')
|
420
|
+
story.destroy
|
418
421
|
expect {
|
419
422
|
story.delay.tell
|
420
|
-
}.to raise_error(ArgumentError,
|
423
|
+
}.to raise_error(ArgumentError, 'Jobs cannot be created for non-persisted records')
|
421
424
|
end
|
422
425
|
end
|
423
426
|
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
job.reload.payload_object
|
430
|
-
|
427
|
+
context "when reload jobs back" do
|
428
|
+
it "reloads changed attributes" do
|
429
|
+
story = Story.create(:text => 'hello')
|
430
|
+
job = story.delay.tell
|
431
|
+
story.update_attributes :text => 'goodbye'
|
432
|
+
expect(job.reload.payload_object.object.text).to eq('goodbye')
|
433
|
+
end
|
434
|
+
|
435
|
+
it "raises deserialization error for destroyed records" do
|
436
|
+
story = Story.create(:text => 'hello')
|
437
|
+
job = story.delay.tell
|
438
|
+
story.destroy
|
439
|
+
expect {
|
440
|
+
job.reload.payload_object
|
441
|
+
}.to raise_error(Delayed::DeserializationError)
|
442
|
+
end
|
431
443
|
end
|
432
444
|
end
|
433
445
|
|
@@ -504,8 +516,8 @@ shared_examples_for "a delayed_job backend" do
|
|
504
516
|
|
505
517
|
it "does not fail when the triggered error doesn't have a message" do
|
506
518
|
error_with_nil_message = StandardError.new
|
507
|
-
error_with_nil_message.
|
508
|
-
@job.
|
519
|
+
expect(error_with_nil_message).to receive(:message).twice.and_return(nil)
|
520
|
+
expect(@job).to receive(:invoke_job).and_raise error_with_nil_message
|
509
521
|
expect{worker.run(@job)}.not_to raise_error
|
510
522
|
end
|
511
523
|
end
|
@@ -519,27 +531,25 @@ shared_examples_for "a delayed_job backend" do
|
|
519
531
|
context "when the job's payload has a #failure hook" do
|
520
532
|
before do
|
521
533
|
@job = Delayed::Job.create :payload_object => OnPermanentFailureJob.new
|
522
|
-
expect(@job.payload_object).to respond_to
|
534
|
+
expect(@job.payload_object).to respond_to(:failure)
|
523
535
|
end
|
524
536
|
|
525
537
|
it "runs that hook" do
|
526
|
-
@job.payload_object.
|
538
|
+
expect(@job.payload_object).to receive(:failure)
|
527
539
|
worker.reschedule(@job)
|
528
540
|
end
|
529
541
|
end
|
530
542
|
|
531
543
|
context "when the job's payload has no #failure hook" do
|
532
544
|
# It's a little tricky to test this in a straightforward way,
|
533
|
-
# because putting a
|
534
|
-
# @job.payload_object.failure makes that object
|
535
|
-
#
|
536
|
-
#
|
537
|
-
#
|
538
|
-
#
|
539
|
-
#
|
540
|
-
#
|
541
|
-
# don't get a NoMethodError (caused by calling that nonexistent
|
542
|
-
# failure method).
|
545
|
+
# because putting a not_to receive expectation on
|
546
|
+
# @job.payload_object.failure makes that object incorrectly return
|
547
|
+
# true to payload_object.respond_to? :failure, which is what
|
548
|
+
# reschedule uses to decide whether to call failure. So instead, we
|
549
|
+
# just make sure that the payload_object as it already stands doesn't
|
550
|
+
# respond_to? failure, then shove it through the iterated reschedule
|
551
|
+
# loop and make sure we don't get a NoMethodError (caused by calling
|
552
|
+
# that nonexistent failure method).
|
543
553
|
|
544
554
|
before do
|
545
555
|
expect(@job.payload_object).not_to respond_to(:failure)
|
@@ -557,12 +567,12 @@ shared_examples_for "a delayed_job backend" do
|
|
557
567
|
it_should_behave_like "any failure more than Worker.max_attempts times"
|
558
568
|
|
559
569
|
it "is destroyed if it failed more than Worker.max_attempts times" do
|
560
|
-
@job.
|
570
|
+
expect(@job).to receive(:destroy)
|
561
571
|
Delayed::Worker.max_attempts.times { worker.reschedule(@job) }
|
562
572
|
end
|
563
573
|
|
564
574
|
it "is not destroyed if failed fewer than Worker.max_attempts times" do
|
565
|
-
@job.
|
575
|
+
expect(@job).not_to receive(:destroy)
|
566
576
|
(Delayed::Worker.max_attempts - 1).times { worker.reschedule(@job) }
|
567
577
|
end
|
568
578
|
end
|
data/lib/delayed/exceptions.rb
CHANGED
@@ -9,8 +9,8 @@ module Delayed
|
|
9
9
|
def initialize(object, method_name, args)
|
10
10
|
raise NoMethodError, "undefined method `#{method_name}' for #{object.inspect}" unless object.respond_to?(method_name, true)
|
11
11
|
|
12
|
-
if object.respond_to?(:
|
13
|
-
raise(ArgumentError, 'Jobs cannot be created for records
|
12
|
+
if object.respond_to?(:persisted?) && !object.persisted?
|
13
|
+
raise(ArgumentError, 'Jobs cannot be created for non-persisted records')
|
14
14
|
end
|
15
15
|
|
16
16
|
self.object = object
|
data/lib/delayed/railtie.rb
CHANGED
data/lib/delayed/worker.rb
CHANGED
@@ -7,8 +7,9 @@ require 'logger'
|
|
7
7
|
require 'benchmark'
|
8
8
|
|
9
9
|
module Delayed
|
10
|
+
|
10
11
|
class Worker
|
11
|
-
DEFAULT_LOG_LEVEL =
|
12
|
+
DEFAULT_LOG_LEVEL = 'info'
|
12
13
|
DEFAULT_SLEEP_DELAY = 5
|
13
14
|
DEFAULT_MAX_ATTEMPTS = 25
|
14
15
|
DEFAULT_MAX_RUN_TIME = 4.hours
|
@@ -225,7 +226,7 @@ module Delayed
|
|
225
226
|
job.unlock
|
226
227
|
job.save!
|
227
228
|
else
|
228
|
-
job_say job, "REMOVED permanently because of #{job.attempts} consecutive failures",
|
229
|
+
job_say job, "REMOVED permanently because of #{job.attempts} consecutive failures", 'error'
|
229
230
|
failed(job)
|
230
231
|
end
|
231
232
|
end
|
@@ -245,7 +246,13 @@ module Delayed
|
|
245
246
|
def say(text, level = DEFAULT_LOG_LEVEL)
|
246
247
|
text = "[Worker(#{name})] #{text}"
|
247
248
|
puts text unless @quiet
|
248
|
-
|
249
|
+
if logger
|
250
|
+
# TODO: Deprecate use of Fixnum log levels
|
251
|
+
if !level.is_a?(String)
|
252
|
+
level = Logger::Severity.constants.detect {|i| Logger::Severity.const_get(i) == level }.to_s.downcase
|
253
|
+
end
|
254
|
+
logger.send(level, "#{Time.now.strftime('%FT%T%z')}: #{text}")
|
255
|
+
end
|
249
256
|
end
|
250
257
|
|
251
258
|
def max_attempts(job)
|
@@ -256,7 +263,7 @@ module Delayed
|
|
256
263
|
|
257
264
|
def handle_failed_job(job, error)
|
258
265
|
job.last_error = "#{error.message}\n#{error.backtrace.join("\n")}"
|
259
|
-
job_say job, "FAILED (#{job.attempts} prior attempts) with #{error.class.name}: #{error.message}",
|
266
|
+
job_say job, "FAILED (#{job.attempts} prior attempts) with #{error.class.name}: #{error.message}", 'error'
|
260
267
|
reschedule(job)
|
261
268
|
end
|
262
269
|
|
data/spec/helper.rb
CHANGED
@@ -26,7 +26,7 @@ Delayed::Worker.backend = :test
|
|
26
26
|
ActiveSupport::Dependencies.autoload_paths << File.dirname(__FILE__)
|
27
27
|
|
28
28
|
# Add this to simulate Railtie initializer being executed
|
29
|
-
ActionMailer::Base.
|
29
|
+
ActionMailer::Base.extend(Delayed::DelayMail)
|
30
30
|
|
31
31
|
|
32
32
|
# Used to test interactions between DJ and an ORM
|
data/spec/lifecycle_spec.rb
CHANGED
@@ -13,8 +13,8 @@ describe Delayed::Lifecycle do
|
|
13
13
|
end
|
14
14
|
|
15
15
|
it "executes before wrapped block" do
|
16
|
-
callback.
|
17
|
-
behavior.
|
16
|
+
expect(callback).to receive(:call).with(*arguments).ordered
|
17
|
+
expect(behavior).to receive(:inside!).ordered
|
18
18
|
lifecycle.run_callbacks :execute, *arguments, &wrapped_block
|
19
19
|
end
|
20
20
|
end
|
@@ -25,8 +25,8 @@ describe Delayed::Lifecycle do
|
|
25
25
|
end
|
26
26
|
|
27
27
|
it "executes after wrapped block" do
|
28
|
-
behavior.
|
29
|
-
callback.
|
28
|
+
expect(behavior).to receive(:inside!).ordered
|
29
|
+
expect(callback).to receive(:call).with(*arguments).ordered
|
30
30
|
lifecycle.run_callbacks :execute, *arguments, &wrapped_block
|
31
31
|
end
|
32
32
|
end
|
@@ -41,16 +41,16 @@ describe Delayed::Lifecycle do
|
|
41
41
|
end
|
42
42
|
|
43
43
|
it "wraps a block" do
|
44
|
-
behavior.
|
45
|
-
behavior.
|
46
|
-
behavior.
|
44
|
+
expect(behavior).to receive(:before!).ordered
|
45
|
+
expect(behavior).to receive(:inside!).ordered
|
46
|
+
expect(behavior).to receive(:after!).ordered
|
47
47
|
lifecycle.run_callbacks :execute, *arguments, &wrapped_block
|
48
48
|
end
|
49
49
|
|
50
50
|
it "executes multiple callbacks in order" do
|
51
|
-
behavior.
|
52
|
-
behavior.
|
53
|
-
behavior.
|
51
|
+
expect(behavior).to receive(:one).ordered
|
52
|
+
expect(behavior).to receive(:two).ordered
|
53
|
+
expect(behavior).to receive(:three).ordered
|
54
54
|
|
55
55
|
lifecycle.around(:execute) { |*args, &block| behavior.one; block.call(*args) }
|
56
56
|
lifecycle.around(:execute) { |*args, &block| behavior.two; block.call(*args) }
|
@@ -34,8 +34,8 @@ describe ActionMailer::Base do
|
|
34
34
|
mailer_class = double('MailerClass', :signup => email)
|
35
35
|
mailer = Delayed::PerformableMailer.new(mailer_class, :signup, ['john@example.com'])
|
36
36
|
|
37
|
-
mailer_class.
|
38
|
-
email.
|
37
|
+
expect(mailer_class).to receive(:signup).with('john@example.com')
|
38
|
+
expect(email).to receive(:deliver)
|
39
39
|
mailer.perform
|
40
40
|
end
|
41
41
|
end
|
@@ -17,7 +17,7 @@ describe Delayed::PerformableMethod do
|
|
17
17
|
end
|
18
18
|
|
19
19
|
it "calls the method on the object" do
|
20
|
-
@method.object.
|
20
|
+
expect(@method.object).to receive(:count).with('o')
|
21
21
|
@method.perform
|
22
22
|
end
|
23
23
|
end
|
@@ -45,7 +45,7 @@ describe Delayed::PerformableMethod do
|
|
45
45
|
story = Story.create
|
46
46
|
job = story.delay.tell
|
47
47
|
|
48
|
-
story.
|
48
|
+
expect(story).to receive(hook).with(job)
|
49
49
|
job.invoke_job
|
50
50
|
end
|
51
51
|
end
|
@@ -55,34 +55,34 @@ describe Delayed::PerformableMethod do
|
|
55
55
|
story = Story.create
|
56
56
|
job = story.delay.tell
|
57
57
|
|
58
|
-
story.
|
58
|
+
expect(story).to receive(hook).with(job)
|
59
59
|
job.invoke_job
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
63
|
it "delegates enqueue hook to object" do
|
64
64
|
story = Story.create
|
65
|
-
story.
|
65
|
+
expect(story).to receive(:enqueue).with(an_instance_of(Delayed::Job))
|
66
66
|
story.delay.tell
|
67
67
|
end
|
68
68
|
|
69
69
|
it "delegates error hook to object" do
|
70
70
|
story = Story.create
|
71
|
-
story.
|
72
|
-
story.
|
71
|
+
expect(story).to receive(:error).with(an_instance_of(Delayed::Job), an_instance_of(RuntimeError))
|
72
|
+
expect(story).to receive(:tell).and_raise(RuntimeError)
|
73
73
|
expect { story.delay.tell.invoke_job }.to raise_error
|
74
74
|
end
|
75
75
|
|
76
76
|
it "delegates error hook to object when delay_jobs = false" do
|
77
77
|
story = Story.create
|
78
|
-
story.
|
79
|
-
story.
|
78
|
+
expect(story).to receive(:error).with(an_instance_of(Delayed::Job), an_instance_of(RuntimeError))
|
79
|
+
expect(story).to receive(:tell).and_raise(RuntimeError)
|
80
80
|
expect { story.delay.tell.invoke_job }.to raise_error
|
81
81
|
end
|
82
82
|
|
83
83
|
it "delegates failure hook to object" do
|
84
84
|
method = Delayed::PerformableMethod.new("object", :size, [])
|
85
|
-
method.object.
|
85
|
+
expect(method.object).to receive(:failure)
|
86
86
|
method.failure
|
87
87
|
end
|
88
88
|
|
@@ -98,7 +98,7 @@ describe Delayed::PerformableMethod do
|
|
98
98
|
%w(before after success).each do |hook|
|
99
99
|
it "delegates #{hook} hook to object" do
|
100
100
|
story = Story.create
|
101
|
-
story.
|
101
|
+
expect(story).to receive(hook).with(an_instance_of(Delayed::Job))
|
102
102
|
story.delay.tell
|
103
103
|
end
|
104
104
|
end
|
@@ -106,29 +106,29 @@ describe Delayed::PerformableMethod do
|
|
106
106
|
%w(before after success).each do |hook|
|
107
107
|
it "delegates #{hook} hook to object" do
|
108
108
|
story = Story.create
|
109
|
-
story.
|
109
|
+
expect(story).to receive(hook).with(an_instance_of(Delayed::Job))
|
110
110
|
story.delay.tell
|
111
111
|
end
|
112
112
|
end
|
113
113
|
|
114
114
|
it "delegates error hook to object" do
|
115
115
|
story = Story.create
|
116
|
-
story.
|
117
|
-
story.
|
116
|
+
expect(story).to receive(:error).with(an_instance_of(Delayed::Job), an_instance_of(RuntimeError))
|
117
|
+
expect(story).to receive(:tell).and_raise(RuntimeError)
|
118
118
|
expect { story.delay.tell }.to raise_error
|
119
119
|
end
|
120
120
|
|
121
121
|
it "delegates error hook to object when delay_jobs = false" do
|
122
122
|
story = Story.create
|
123
|
-
story.
|
124
|
-
story.
|
123
|
+
expect(story).to receive(:error).with(an_instance_of(Delayed::Job), an_instance_of(RuntimeError))
|
124
|
+
expect(story).to receive(:tell).and_raise(RuntimeError)
|
125
125
|
expect { story.delay.tell }.to raise_error
|
126
126
|
end
|
127
127
|
|
128
128
|
it "delegates failure hook to object when delay_jobs = false" do
|
129
129
|
Delayed::Worker.delay_jobs = false
|
130
130
|
method = Delayed::PerformableMethod.new("object", :size, [])
|
131
|
-
method.object.
|
131
|
+
expect(method.object).to receive(:failure)
|
132
132
|
method.failure
|
133
133
|
end
|
134
134
|
end
|
data/spec/worker_spec.rb
CHANGED
@@ -28,7 +28,7 @@ describe Delayed::Worker do
|
|
28
28
|
end
|
29
29
|
|
30
30
|
it "logs with job name and id" do
|
31
|
-
@worker.
|
31
|
+
expect(@worker).to receive(:say).
|
32
32
|
with('Job ExampleJob (id=123) message', Delayed::Worker::DEFAULT_LOG_LEVEL)
|
33
33
|
@worker.job_say(@job, 'message')
|
34
34
|
end
|
@@ -44,13 +44,13 @@ describe Delayed::Worker do
|
|
44
44
|
end
|
45
45
|
|
46
46
|
it "reads five jobs" do
|
47
|
-
Delayed::Job.
|
47
|
+
expect(Delayed::Job).to receive(:find_available).with(anything, 5, anything).and_return([])
|
48
48
|
Delayed::Job.reserve(Delayed::Worker.new)
|
49
49
|
end
|
50
50
|
|
51
51
|
it "reads a configurable number of jobs" do
|
52
52
|
Delayed::Worker.read_ahead = 15
|
53
|
-
Delayed::Job.
|
53
|
+
expect(Delayed::Job).to receive(:find_available).with(anything, Delayed::Worker.read_ahead, anything).and_return([])
|
54
54
|
Delayed::Job.reserve(Delayed::Worker.new)
|
55
55
|
end
|
56
56
|
end
|
@@ -82,21 +82,68 @@ describe Delayed::Worker do
|
|
82
82
|
end
|
83
83
|
|
84
84
|
it "handles error during job reservation" do
|
85
|
-
Delayed::Job.
|
85
|
+
expect(Delayed::Job).to receive(:reserve).and_raise(Exception)
|
86
86
|
Delayed::Worker.new.work_off
|
87
87
|
end
|
88
88
|
|
89
89
|
it "gives up after 10 backend failures" do
|
90
|
-
Delayed::Job.
|
90
|
+
expect(Delayed::Job).to receive(:reserve).exactly(10).times.and_raise(Exception)
|
91
91
|
worker = Delayed::Worker.new
|
92
92
|
9.times { worker.work_off }
|
93
|
-
expect(lambda { worker.work_off }).to raise_exception
|
93
|
+
expect(lambda { worker.work_off }).to raise_exception Delayed::FatalBackendError
|
94
94
|
end
|
95
95
|
|
96
96
|
it "allows the backend to attempt recovery from reservation errors" do
|
97
|
-
Delayed::Job.
|
98
|
-
Delayed::Job.
|
97
|
+
expect(Delayed::Job).to receive(:reserve).and_raise(Exception)
|
98
|
+
expect(Delayed::Job).to receive(:recover_from).with(instance_of(Exception))
|
99
99
|
Delayed::Worker.new.work_off
|
100
100
|
end
|
101
101
|
end
|
102
|
+
|
103
|
+
context "#say" do
|
104
|
+
before(:each) do
|
105
|
+
@worker = Delayed::Worker.new
|
106
|
+
@worker.name = 'ExampleJob'
|
107
|
+
@worker.logger = double('job')
|
108
|
+
time = Time.now
|
109
|
+
Time.stub(:now).and_return(time)
|
110
|
+
@text = "Job executed"
|
111
|
+
@worker_name = "[Worker(ExampleJob)]"
|
112
|
+
@expected_time = time.strftime('%FT%T%z')
|
113
|
+
end
|
114
|
+
|
115
|
+
after(:each) do
|
116
|
+
@worker.logger = nil
|
117
|
+
end
|
118
|
+
|
119
|
+
shared_examples_for "a worker which logs on the correct severity" do |severity|
|
120
|
+
it "logs a message on the #{severity[:level].upcase} level given a string" do
|
121
|
+
expect(@worker.logger).to receive(:send).
|
122
|
+
with(severity[:level], "#{@expected_time}: #{@worker_name} #{@text}")
|
123
|
+
@worker.say(@text, severity[:level])
|
124
|
+
end
|
125
|
+
|
126
|
+
it "logs a message on the #{severity[:level].upcase} level given a fixnum" do
|
127
|
+
expect(@worker.logger).to receive(:send).
|
128
|
+
with(severity[:level], "#{@expected_time}: #{@worker_name} #{@text}")
|
129
|
+
@worker.say(@text, severity[:index])
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
severities = [ { index: 0, level: "debug" },
|
134
|
+
{ index: 1, level: "info" },
|
135
|
+
{ index: 2, level: "warn" },
|
136
|
+
{ index: 3, level: "error" },
|
137
|
+
{ index: 4, level: "fatal" },
|
138
|
+
{ index: 5, level: "unknown" } ]
|
139
|
+
severities.each do |severity|
|
140
|
+
it_behaves_like "a worker which logs on the correct severity", severity
|
141
|
+
end
|
142
|
+
|
143
|
+
it "logs a message on the default log's level" do
|
144
|
+
expect(@worker.logger).to receive(:send).
|
145
|
+
with("info", "#{@expected_time}: #{@worker_name} #{@text}")
|
146
|
+
@worker.say(@text, Delayed::Worker::DEFAULT_LOG_LEVEL)
|
147
|
+
end
|
148
|
+
end
|
102
149
|
end
|
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: delayed_job
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.
|
5
|
-
prerelease:
|
4
|
+
version: 4.0.1
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Brandon Keepers
|
@@ -16,30 +15,28 @@ authors:
|
|
16
15
|
autorequire:
|
17
16
|
bindir: bin
|
18
17
|
cert_chain: []
|
19
|
-
date:
|
18
|
+
date: 2014-04-12 00:00:00.000000000 Z
|
20
19
|
dependencies:
|
21
20
|
- !ruby/object:Gem::Dependency
|
22
21
|
name: activesupport
|
23
22
|
requirement: !ruby/object:Gem::Requirement
|
24
|
-
none: false
|
25
23
|
requirements:
|
26
|
-
- -
|
24
|
+
- - ">="
|
27
25
|
- !ruby/object:Gem::Version
|
28
26
|
version: '3.0'
|
29
|
-
- - <
|
27
|
+
- - "<"
|
30
28
|
- !ruby/object:Gem::Version
|
31
|
-
version: '4.
|
29
|
+
version: '4.2'
|
32
30
|
type: :runtime
|
33
31
|
prerelease: false
|
34
32
|
version_requirements: !ruby/object:Gem::Requirement
|
35
|
-
none: false
|
36
33
|
requirements:
|
37
|
-
- -
|
34
|
+
- - ">="
|
38
35
|
- !ruby/object:Gem::Version
|
39
36
|
version: '3.0'
|
40
|
-
- - <
|
37
|
+
- - "<"
|
41
38
|
- !ruby/object:Gem::Version
|
42
|
-
version: '4.
|
39
|
+
version: '4.2'
|
43
40
|
description: Delayed_job (or DJ) encapsulates the common pattern of asynchronously
|
44
41
|
executing longer tasks in the background. It is a direct extraction from Shopify
|
45
42
|
where the job table is responsible for a multitude of core tasks.
|
@@ -54,11 +51,11 @@ files:
|
|
54
51
|
- LICENSE.md
|
55
52
|
- README.md
|
56
53
|
- Rakefile
|
57
|
-
- delayed_job.gemspec
|
58
54
|
- contrib/delayed_job.monitrc
|
59
55
|
- contrib/delayed_job_multiple.monitrc
|
60
56
|
- contrib/delayed_job_rails_4.monitrc
|
61
57
|
- contrib/delayed_job_rails_4_multiple.monitrc
|
58
|
+
- delayed_job.gemspec
|
62
59
|
- lib/delayed/backend/base.rb
|
63
60
|
- lib/delayed/backend/shared_spec.rb
|
64
61
|
- lib/delayed/command.rb
|
@@ -101,33 +98,26 @@ files:
|
|
101
98
|
homepage: http://github.com/collectiveidea/delayed_job
|
102
99
|
licenses:
|
103
100
|
- MIT
|
101
|
+
metadata: {}
|
104
102
|
post_install_message:
|
105
103
|
rdoc_options: []
|
106
104
|
require_paths:
|
107
105
|
- lib
|
108
106
|
required_ruby_version: !ruby/object:Gem::Requirement
|
109
|
-
none: false
|
110
107
|
requirements:
|
111
|
-
- -
|
108
|
+
- - ">="
|
112
109
|
- !ruby/object:Gem::Version
|
113
110
|
version: '0'
|
114
|
-
segments:
|
115
|
-
- 0
|
116
|
-
hash: 3979399263094595498
|
117
111
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
|
-
none: false
|
119
112
|
requirements:
|
120
|
-
- -
|
113
|
+
- - ">="
|
121
114
|
- !ruby/object:Gem::Version
|
122
115
|
version: '0'
|
123
|
-
segments:
|
124
|
-
- 0
|
125
|
-
hash: 3979399263094595498
|
126
116
|
requirements: []
|
127
117
|
rubyforge_project:
|
128
|
-
rubygems_version:
|
118
|
+
rubygems_version: 2.2.2
|
129
119
|
signing_key:
|
130
|
-
specification_version:
|
120
|
+
specification_version: 4
|
131
121
|
summary: Database-backed asynchronous priority queue system -- Extracted from Shopify
|
132
122
|
test_files:
|
133
123
|
- spec/autoloaded/clazz.rb
|