delayed_job 4.0.4 → 4.0.5
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +25 -4
- data/delayed_job.gemspec +4 -5
- data/lib/delayed/psych_ext.rb +3 -1
- data/lib/delayed/railtie.rb +1 -1
- data/lib/delayed/tasks.rb +0 -2
- data/lib/delayed/worker.rb +11 -0
- metadata +6 -41
- data/Rakefile +0 -15
- data/spec/autoloaded/clazz.rb +0 -7
- data/spec/autoloaded/instance_clazz.rb +0 -6
- data/spec/autoloaded/instance_struct.rb +0 -6
- data/spec/autoloaded/struct.rb +0 -7
- data/spec/delayed/backend/test.rb +0 -117
- data/spec/delayed/command_spec.rb +0 -57
- data/spec/delayed/serialization/test.rb +0 -0
- data/spec/helper.rb +0 -85
- data/spec/lifecycle_spec.rb +0 -75
- data/spec/message_sending_spec.rb +0 -122
- data/spec/performable_mailer_spec.rb +0 -44
- data/spec/performable_method_spec.rb +0 -144
- data/spec/psych_ext_spec.rb +0 -12
- data/spec/sample_jobs.rb +0 -109
- data/spec/test_backend_spec.rb +0 -13
- data/spec/worker_spec.rb +0 -157
- data/spec/yaml_ext_spec.rb +0 -48
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7aeb53385b816641ccbee1ffeb9571f8a9fc277f
|
4
|
+
data.tar.gz: 54d26795c4f7f72f5c70e63e8ec0eca4c937def8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5bacca5b8cdb6ebd37341a7f574f00da50b1d201b6f453840b2123a84bd19c865cba84b090d9f2e85d11f75b233f3e0d4ce484cc674627a9146a1f551f89b933
|
7
|
+
data.tar.gz: 85db710c5c82ed12d7d230fbee0be2b3921275c4c174b921620d91491be6d320a7fda7b1335fb8bcfe6a5c878552425d00acfb48d0a1298d62dd7d30f53424f3
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
4.0.5 - 2014-12-22
|
2
|
+
==================
|
3
|
+
* Support for Rails 4.2
|
4
|
+
* Allow user to override where DJ writes log output
|
5
|
+
* First attempt at automatic code reloading
|
6
|
+
* Clearer error message when ActiveRecord object no longer exists
|
7
|
+
* Various improvements to the README
|
8
|
+
|
1
9
|
4.0.4 - 2014-09-24
|
2
10
|
==================
|
3
11
|
* Fix using options passed into delayed_job command
|
data/README.md
CHANGED
@@ -58,6 +58,11 @@ running the following command:
|
|
58
58
|
rails generate delayed_job:active_record
|
59
59
|
rake db:migrate
|
60
60
|
|
61
|
+
Development
|
62
|
+
===========
|
63
|
+
In development mode, if you are using Rails 3.1+, your application code will automatically reload every 100 jobs or when the queue finishes.
|
64
|
+
You no longer need to restart Delayed Job every time you update your code in development.
|
65
|
+
|
61
66
|
Rails 4
|
62
67
|
=======
|
63
68
|
If you are using the protected_attributes gem, it must appear before delayed_job in your gemfile.
|
@@ -119,10 +124,12 @@ class LongTasks
|
|
119
124
|
2.hours.from_now
|
120
125
|
end
|
121
126
|
|
122
|
-
|
123
|
-
|
127
|
+
class << self
|
128
|
+
def call_a_class_method
|
129
|
+
# Some other code
|
130
|
+
end
|
131
|
+
handle_asynchronously :call_a_class_method, :run_at => Proc.new { when_to_run }
|
124
132
|
end
|
125
|
-
handle_asynchronously :call_a_class_method, :run_at => Proc.new { when_to_run }
|
126
133
|
|
127
134
|
attr_reader :how_important
|
128
135
|
|
@@ -289,6 +296,19 @@ NewsletterJob = Struct.new(:text, :emails) do
|
|
289
296
|
end
|
290
297
|
```
|
291
298
|
|
299
|
+
On error, the job is scheduled again in 5 seconds + N ** 4, where N is the number of attempts. You can define your own `reschedule_at` method to override this default behavior.
|
300
|
+
|
301
|
+
```ruby
|
302
|
+
NewsletterJob = Struct.new(:text, :emails) do
|
303
|
+
def perform
|
304
|
+
emails.each { |e| NewsletterMailer.deliver_text_to_email(text, e) }
|
305
|
+
end
|
306
|
+
|
307
|
+
def reschedule_at(current_time, attempts)
|
308
|
+
current_time + 5.seconds
|
309
|
+
end
|
310
|
+
end
|
311
|
+
```
|
292
312
|
|
293
313
|
Hooks
|
294
314
|
=====
|
@@ -345,7 +365,7 @@ create_table :delayed_jobs, :force => true do |table|
|
|
345
365
|
end
|
346
366
|
```
|
347
367
|
|
348
|
-
On
|
368
|
+
On error, the job is scheduled again in 5 seconds + N ** 4, where N is the number of attempts or using the job's defined `reschedule_at` method.
|
349
369
|
|
350
370
|
The default `Worker.max_attempts` is 25. After this, the job either deleted (default), or left in the database with "failed_at" set.
|
351
371
|
With the default of 25 attempts, the last retry will be 20 days later, with the last interval being almost 100 hours.
|
@@ -378,6 +398,7 @@ Delayed::Worker.read_ahead = 10
|
|
378
398
|
Delayed::Worker.default_queue_name = 'default'
|
379
399
|
Delayed::Worker.delay_jobs = !Rails.env.test?
|
380
400
|
Delayed::Worker.raise_signal_exceptions = :term
|
401
|
+
Delayed::Worker.logger = Logger.new(File.join(Rails.root, 'log', 'delayed_job.log'))
|
381
402
|
```
|
382
403
|
|
383
404
|
Cleaning up
|
data/delayed_job.gemspec
CHANGED
@@ -1,15 +1,14 @@
|
|
1
1
|
Gem::Specification.new do |spec|
|
2
|
-
spec.add_dependency 'activesupport', ['>= 3.0', '<
|
2
|
+
spec.add_dependency 'activesupport', ['>= 3.0', '< 5.0']
|
3
3
|
spec.authors = ['Brandon Keepers', 'Brian Ryckbost', 'Chris Gaffney', 'David Genord II', 'Erik Michaels-Ober', 'Matt Griffin', 'Steve Richert', 'Tobias Lütke']
|
4
4
|
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.'
|
5
5
|
spec.email = ['brian@collectiveidea.com']
|
6
|
-
spec.files = %w[CHANGELOG.md CONTRIBUTING.md LICENSE.md README.md
|
7
|
-
spec.files += Dir
|
6
|
+
spec.files = %w[CHANGELOG.md CONTRIBUTING.md LICENSE.md README.md delayed_job.gemspec]
|
7
|
+
spec.files += Dir['{contrib,lib,recipes}/**/*']
|
8
8
|
spec.homepage = 'http://github.com/collectiveidea/delayed_job'
|
9
9
|
spec.licenses = ['MIT']
|
10
10
|
spec.name = 'delayed_job'
|
11
11
|
spec.require_paths = ['lib']
|
12
12
|
spec.summary = 'Database-backed asynchronous priority queue system -- Extracted from Shopify'
|
13
|
-
spec.
|
14
|
-
spec.version = '4.0.4'
|
13
|
+
spec.version = '4.0.5'
|
15
14
|
end
|
data/lib/delayed/psych_ext.rb
CHANGED
@@ -34,8 +34,10 @@ module Delayed
|
|
34
34
|
when /^!ruby\/object/
|
35
35
|
result = super
|
36
36
|
if defined?(ActiveRecord::Base) && result.is_a?(ActiveRecord::Base)
|
37
|
+
klass = result.class
|
38
|
+
id = result[klass.primary_key]
|
37
39
|
begin
|
38
|
-
|
40
|
+
klass.find(id)
|
39
41
|
rescue ActiveRecord::RecordNotFound => error # rubocop:disable BlockNesting
|
40
42
|
raise Delayed::DeserializationError, "ActiveRecord::RecordNotFound, class: #{klass}, primary key: #{id} (#{error.message})"
|
41
43
|
end
|
data/lib/delayed/railtie.rb
CHANGED
data/lib/delayed/tasks.rb
CHANGED
data/lib/delayed/worker.rb
CHANGED
@@ -100,6 +100,10 @@ module Delayed
|
|
100
100
|
@lifecycle ||= Delayed::Lifecycle.new
|
101
101
|
end
|
102
102
|
|
103
|
+
def self.reload_app?
|
104
|
+
defined?(ActionDispatch::Reloader) && Rails.application.config.cache_classes == false
|
105
|
+
end
|
106
|
+
|
103
107
|
def initialize(options = {})
|
104
108
|
@quiet = options.key?(:quiet) ? options[:quiet] : true
|
105
109
|
@failed_reserve_count = 0
|
@@ -155,6 +159,7 @@ module Delayed
|
|
155
159
|
break
|
156
160
|
elsif !stop?
|
157
161
|
sleep(self.class.sleep_delay)
|
162
|
+
reload!
|
158
163
|
end
|
159
164
|
else
|
160
165
|
say format("#{count} jobs processed at %.4f j/s, %d failed", count / @realtime, @result.last)
|
@@ -286,5 +291,11 @@ module Delayed
|
|
286
291
|
raise FatalBackendError if @failed_reserve_count >= 10
|
287
292
|
nil
|
288
293
|
end
|
294
|
+
|
295
|
+
def reload!
|
296
|
+
return unless self.class.reload_app?
|
297
|
+
ActionDispatch::Reloader.cleanup!
|
298
|
+
ActionDispatch::Reloader.prepare!
|
299
|
+
end
|
289
300
|
end
|
290
301
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: delayed_job
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.0.
|
4
|
+
version: 4.0.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brandon Keepers
|
@@ -15,7 +15,7 @@ authors:
|
|
15
15
|
autorequire:
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
|
-
date: 2014-
|
18
|
+
date: 2014-12-22 00:00:00.000000000 Z
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
21
|
name: activesupport
|
@@ -26,7 +26,7 @@ dependencies:
|
|
26
26
|
version: '3.0'
|
27
27
|
- - "<"
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
version: '
|
29
|
+
version: '5.0'
|
30
30
|
type: :runtime
|
31
31
|
prerelease: false
|
32
32
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -36,7 +36,7 @@ dependencies:
|
|
36
36
|
version: '3.0'
|
37
37
|
- - "<"
|
38
38
|
- !ruby/object:Gem::Version
|
39
|
-
version: '
|
39
|
+
version: '5.0'
|
40
40
|
description: Delayed_job (or DJ) encapsulates the common pattern of asynchronously
|
41
41
|
executing longer tasks in the background. It is a direct extraction from Shopify
|
42
42
|
where the job table is responsible for a multitude of core tasks.
|
@@ -50,7 +50,6 @@ files:
|
|
50
50
|
- CONTRIBUTING.md
|
51
51
|
- LICENSE.md
|
52
52
|
- README.md
|
53
|
-
- Rakefile
|
54
53
|
- contrib/delayed_job.monitrc
|
55
54
|
- contrib/delayed_job_multiple.monitrc
|
56
55
|
- contrib/delayed_job_rails_4.monitrc
|
@@ -80,23 +79,6 @@ files:
|
|
80
79
|
- lib/generators/delayed_job/delayed_job_generator.rb
|
81
80
|
- lib/generators/delayed_job/templates/script
|
82
81
|
- recipes/delayed_job.rb
|
83
|
-
- spec/autoloaded/clazz.rb
|
84
|
-
- spec/autoloaded/instance_clazz.rb
|
85
|
-
- spec/autoloaded/instance_struct.rb
|
86
|
-
- spec/autoloaded/struct.rb
|
87
|
-
- spec/delayed/backend/test.rb
|
88
|
-
- spec/delayed/command_spec.rb
|
89
|
-
- spec/delayed/serialization/test.rb
|
90
|
-
- spec/helper.rb
|
91
|
-
- spec/lifecycle_spec.rb
|
92
|
-
- spec/message_sending_spec.rb
|
93
|
-
- spec/performable_mailer_spec.rb
|
94
|
-
- spec/performable_method_spec.rb
|
95
|
-
- spec/psych_ext_spec.rb
|
96
|
-
- spec/sample_jobs.rb
|
97
|
-
- spec/test_backend_spec.rb
|
98
|
-
- spec/worker_spec.rb
|
99
|
-
- spec/yaml_ext_spec.rb
|
100
82
|
homepage: http://github.com/collectiveidea/delayed_job
|
101
83
|
licenses:
|
102
84
|
- MIT
|
@@ -117,25 +99,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
117
99
|
version: '0'
|
118
100
|
requirements: []
|
119
101
|
rubyforge_project:
|
120
|
-
rubygems_version: 2.
|
102
|
+
rubygems_version: 2.4.4
|
121
103
|
signing_key:
|
122
104
|
specification_version: 4
|
123
105
|
summary: Database-backed asynchronous priority queue system -- Extracted from Shopify
|
124
|
-
test_files:
|
125
|
-
- spec/autoloaded/clazz.rb
|
126
|
-
- spec/autoloaded/instance_clazz.rb
|
127
|
-
- spec/autoloaded/instance_struct.rb
|
128
|
-
- spec/autoloaded/struct.rb
|
129
|
-
- spec/delayed/backend/test.rb
|
130
|
-
- spec/delayed/command_spec.rb
|
131
|
-
- spec/delayed/serialization/test.rb
|
132
|
-
- spec/helper.rb
|
133
|
-
- spec/lifecycle_spec.rb
|
134
|
-
- spec/message_sending_spec.rb
|
135
|
-
- spec/performable_mailer_spec.rb
|
136
|
-
- spec/performable_method_spec.rb
|
137
|
-
- spec/psych_ext_spec.rb
|
138
|
-
- spec/sample_jobs.rb
|
139
|
-
- spec/test_backend_spec.rb
|
140
|
-
- spec/worker_spec.rb
|
141
|
-
- spec/yaml_ext_spec.rb
|
106
|
+
test_files: []
|
data/Rakefile
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
require 'bundler/setup'
|
2
|
-
Bundler::GemHelper.install_tasks
|
3
|
-
|
4
|
-
require 'rspec/core/rake_task'
|
5
|
-
desc 'Run the specs'
|
6
|
-
RSpec::Core::RakeTask.new do |r|
|
7
|
-
r.verbose = false
|
8
|
-
end
|
9
|
-
|
10
|
-
task :test => :spec
|
11
|
-
|
12
|
-
require 'rubocop/rake_task'
|
13
|
-
RuboCop::RakeTask.new
|
14
|
-
|
15
|
-
task :default => [:spec, :rubocop]
|
data/spec/autoloaded/clazz.rb
DELETED
data/spec/autoloaded/struct.rb
DELETED
@@ -1,117 +0,0 @@
|
|
1
|
-
require 'ostruct'
|
2
|
-
|
3
|
-
# An in-memory backend suitable only for testing. Tries to behave as if it were an ORM.
|
4
|
-
module Delayed
|
5
|
-
module Backend
|
6
|
-
module Test
|
7
|
-
class Job
|
8
|
-
attr_accessor :id
|
9
|
-
attr_accessor :priority
|
10
|
-
attr_accessor :attempts
|
11
|
-
attr_accessor :handler
|
12
|
-
attr_accessor :last_error
|
13
|
-
attr_accessor :run_at
|
14
|
-
attr_accessor :locked_at
|
15
|
-
attr_accessor :locked_by
|
16
|
-
attr_accessor :failed_at
|
17
|
-
attr_accessor :queue
|
18
|
-
|
19
|
-
include Delayed::Backend::Base
|
20
|
-
|
21
|
-
cattr_accessor :id
|
22
|
-
self.id = 0
|
23
|
-
|
24
|
-
def initialize(hash = {})
|
25
|
-
self.attempts = 0
|
26
|
-
self.priority = 0
|
27
|
-
self.id = (self.class.id += 1)
|
28
|
-
hash.each { |k, v| send(:"#{k}=", v) }
|
29
|
-
end
|
30
|
-
|
31
|
-
def self.all
|
32
|
-
@jobs ||= []
|
33
|
-
end
|
34
|
-
|
35
|
-
def self.count
|
36
|
-
all.size
|
37
|
-
end
|
38
|
-
|
39
|
-
def self.delete_all
|
40
|
-
all.clear
|
41
|
-
end
|
42
|
-
|
43
|
-
def self.create(attrs = {})
|
44
|
-
new(attrs).tap do |o|
|
45
|
-
o.save
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
def self.create!(*args)
|
50
|
-
create(*args)
|
51
|
-
end
|
52
|
-
|
53
|
-
def self.clear_locks!(worker_name)
|
54
|
-
all.select { |j| j.locked_by == worker_name }.each do |j|
|
55
|
-
j.locked_by = nil
|
56
|
-
j.locked_at = nil
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
# Find a few candidate jobs to run (in case some immediately get locked by others).
|
61
|
-
def self.find_available(worker_name, limit = 5, max_run_time = Worker.max_run_time) # rubocop:disable CyclomaticComplexity, PerceivedComplexity
|
62
|
-
jobs = all.select do |j|
|
63
|
-
j.run_at <= db_time_now &&
|
64
|
-
(j.locked_at.nil? || j.locked_at < db_time_now - max_run_time || j.locked_by == worker_name) &&
|
65
|
-
!j.failed?
|
66
|
-
end
|
67
|
-
jobs.select! { |j| j.priority <= Worker.max_priority } if Worker.max_priority
|
68
|
-
jobs.select! { |j| j.priority >= Worker.min_priority } if Worker.min_priority
|
69
|
-
jobs.select! { |j| Worker.queues.include?(j.queue) } if Worker.queues.any?
|
70
|
-
jobs.sort_by! { |j| [j.priority, j.run_at] }[0..limit - 1]
|
71
|
-
end
|
72
|
-
|
73
|
-
# Lock this job for this worker.
|
74
|
-
# Returns true if we have the lock, false otherwise.
|
75
|
-
def lock_exclusively!(_max_run_time, worker)
|
76
|
-
now = self.class.db_time_now
|
77
|
-
if locked_by != worker
|
78
|
-
# We don't own this job so we will update the locked_by name and the locked_at
|
79
|
-
self.locked_at = now
|
80
|
-
self.locked_by = worker
|
81
|
-
end
|
82
|
-
|
83
|
-
true
|
84
|
-
end
|
85
|
-
|
86
|
-
def self.db_time_now
|
87
|
-
Time.current
|
88
|
-
end
|
89
|
-
|
90
|
-
def update_attributes(attrs = {})
|
91
|
-
attrs.each { |k, v| send(:"#{k}=", v) }
|
92
|
-
save
|
93
|
-
end
|
94
|
-
|
95
|
-
def destroy
|
96
|
-
self.class.all.delete(self)
|
97
|
-
end
|
98
|
-
|
99
|
-
def save
|
100
|
-
self.run_at ||= Time.current
|
101
|
-
|
102
|
-
self.class.all << self unless self.class.all.include?(self)
|
103
|
-
true
|
104
|
-
end
|
105
|
-
|
106
|
-
def save!
|
107
|
-
save
|
108
|
-
end
|
109
|
-
|
110
|
-
def reload
|
111
|
-
reset
|
112
|
-
self
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
117
|
-
end
|
@@ -1,57 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
require 'delayed/command'
|
3
|
-
|
4
|
-
describe Delayed::Command do
|
5
|
-
describe 'parsing --pool argument' do
|
6
|
-
it 'should parse --pool correctly' do
|
7
|
-
command = Delayed::Command.new(['--pool=*:1', '--pool=test_queue:4', '--pool=mailers,misc:2'])
|
8
|
-
|
9
|
-
expect(command.worker_pools).to eq [
|
10
|
-
[[], 1],
|
11
|
-
[['test_queue'], 4],
|
12
|
-
[%w[mailers misc], 2]
|
13
|
-
]
|
14
|
-
end
|
15
|
-
|
16
|
-
it 'should allow * or blank to specify any pools' do
|
17
|
-
command = Delayed::Command.new(['--pool=*:4'])
|
18
|
-
expect(command.worker_pools).to eq [
|
19
|
-
[[], 4],
|
20
|
-
]
|
21
|
-
|
22
|
-
command = Delayed::Command.new(['--pool=:4'])
|
23
|
-
expect(command.worker_pools).to eq [
|
24
|
-
[[], 4],
|
25
|
-
]
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'should default to one worker if not specified' do
|
29
|
-
command = Delayed::Command.new(['--pool=mailers'])
|
30
|
-
expect(command.worker_pools).to eq [
|
31
|
-
[['mailers'], 1],
|
32
|
-
]
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
describe 'running worker pools defined by multiple --pool arguments' do
|
37
|
-
it 'should run the correct worker processes' do
|
38
|
-
command = Delayed::Command.new(['--pool=*:1', '--pool=test_queue:4', '--pool=mailers,misc:2'])
|
39
|
-
|
40
|
-
expect(Dir).to receive(:mkdir).with('./tmp/pids').once
|
41
|
-
|
42
|
-
[
|
43
|
-
['delayed_job.0', {:quiet => true, :pid_dir => './tmp/pids', :queues => []}],
|
44
|
-
['delayed_job.1', {:quiet => true, :pid_dir => './tmp/pids', :queues => ['test_queue']}],
|
45
|
-
['delayed_job.2', {:quiet => true, :pid_dir => './tmp/pids', :queues => ['test_queue']}],
|
46
|
-
['delayed_job.3', {:quiet => true, :pid_dir => './tmp/pids', :queues => ['test_queue']}],
|
47
|
-
['delayed_job.4', {:quiet => true, :pid_dir => './tmp/pids', :queues => ['test_queue']}],
|
48
|
-
['delayed_job.5', {:quiet => true, :pid_dir => './tmp/pids', :queues => %w[mailers misc]}],
|
49
|
-
['delayed_job.6', {:quiet => true, :pid_dir => './tmp/pids', :queues => %w[mailers misc]}]
|
50
|
-
].each do |args|
|
51
|
-
expect(command).to receive(:run_process).with(*args).once
|
52
|
-
end
|
53
|
-
|
54
|
-
command.daemonize
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
File without changes
|
data/spec/helper.rb
DELETED
@@ -1,85 +0,0 @@
|
|
1
|
-
require 'simplecov'
|
2
|
-
require 'coveralls'
|
3
|
-
|
4
|
-
SimpleCov.formatters = [SimpleCov::Formatter::HTMLFormatter, Coveralls::SimpleCov::Formatter]
|
5
|
-
|
6
|
-
SimpleCov.start do
|
7
|
-
add_filter '/spec/'
|
8
|
-
# Each version of ruby and version of rails test different things
|
9
|
-
# This should probably just be removed.
|
10
|
-
minimum_coverage(85.0)
|
11
|
-
end
|
12
|
-
|
13
|
-
require 'logger'
|
14
|
-
require 'rspec'
|
15
|
-
|
16
|
-
require 'action_mailer'
|
17
|
-
require 'active_support/dependencies'
|
18
|
-
require 'active_record'
|
19
|
-
|
20
|
-
require 'delayed_job'
|
21
|
-
require 'delayed/backend/shared_spec'
|
22
|
-
|
23
|
-
if ENV['DEBUG_LOGS']
|
24
|
-
Delayed::Worker.logger = Logger.new(STDOUT)
|
25
|
-
else
|
26
|
-
require 'tempfile'
|
27
|
-
|
28
|
-
tf = Tempfile.new('dj.log')
|
29
|
-
Delayed::Worker.logger = Logger.new(tf.path)
|
30
|
-
tf.unlink
|
31
|
-
end
|
32
|
-
ENV['RAILS_ENV'] = 'test'
|
33
|
-
|
34
|
-
# Trigger AR to initialize
|
35
|
-
ActiveRecord::Base # rubocop:disable Void
|
36
|
-
|
37
|
-
module Rails
|
38
|
-
def self.root
|
39
|
-
'.'
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
Delayed::Worker.backend = :test
|
44
|
-
|
45
|
-
# Add this directory so the ActiveSupport autoloading works
|
46
|
-
ActiveSupport::Dependencies.autoload_paths << File.dirname(__FILE__)
|
47
|
-
|
48
|
-
# Add this to simulate Railtie initializer being executed
|
49
|
-
ActionMailer::Base.extend(Delayed::DelayMail)
|
50
|
-
|
51
|
-
# Used to test interactions between DJ and an ORM
|
52
|
-
ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
|
53
|
-
ActiveRecord::Base.logger = Delayed::Worker.logger
|
54
|
-
ActiveRecord::Migration.verbose = false
|
55
|
-
|
56
|
-
ActiveRecord::Schema.define do
|
57
|
-
create_table :stories, :primary_key => :story_id, :force => true do |table|
|
58
|
-
table.string :text
|
59
|
-
table.boolean :scoped, :default => true
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
class Story < ActiveRecord::Base
|
64
|
-
self.primary_key = 'story_id'
|
65
|
-
def tell
|
66
|
-
text
|
67
|
-
end
|
68
|
-
|
69
|
-
def whatever(n, _)
|
70
|
-
tell * n
|
71
|
-
end
|
72
|
-
default_scope { where(:scoped => true) }
|
73
|
-
|
74
|
-
handle_asynchronously :whatever
|
75
|
-
end
|
76
|
-
|
77
|
-
RSpec.configure do |config|
|
78
|
-
config.after(:each) do
|
79
|
-
Delayed::Worker.reset
|
80
|
-
end
|
81
|
-
|
82
|
-
config.expect_with :rspec do |c|
|
83
|
-
c.syntax = :expect
|
84
|
-
end
|
85
|
-
end
|
data/spec/lifecycle_spec.rb
DELETED
@@ -1,75 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
describe Delayed::Lifecycle do
|
4
|
-
let(:lifecycle) { Delayed::Lifecycle.new }
|
5
|
-
let(:callback) { lambda { |*_args| } }
|
6
|
-
let(:arguments) { [1] }
|
7
|
-
let(:behavior) { double(Object, :before! => nil, :after! => nil, :inside! => nil) }
|
8
|
-
let(:wrapped_block) { proc { behavior.inside! } }
|
9
|
-
|
10
|
-
describe 'before callbacks' do
|
11
|
-
before(:each) do
|
12
|
-
lifecycle.before(:execute, &callback)
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'executes before wrapped block' do
|
16
|
-
expect(callback).to receive(:call).with(*arguments).ordered
|
17
|
-
expect(behavior).to receive(:inside!).ordered
|
18
|
-
lifecycle.run_callbacks :execute, *arguments, &wrapped_block
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
describe 'after callbacks' do
|
23
|
-
before(:each) do
|
24
|
-
lifecycle.after(:execute, &callback)
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'executes after wrapped block' do
|
28
|
-
expect(behavior).to receive(:inside!).ordered
|
29
|
-
expect(callback).to receive(:call).with(*arguments).ordered
|
30
|
-
lifecycle.run_callbacks :execute, *arguments, &wrapped_block
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
describe 'around callbacks' do
|
35
|
-
before(:each) do
|
36
|
-
lifecycle.around(:execute) do |*args, &block|
|
37
|
-
behavior.before!
|
38
|
-
block.call(*args)
|
39
|
-
behavior.after!
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'wraps a block' do
|
44
|
-
expect(behavior).to receive(:before!).ordered
|
45
|
-
expect(behavior).to receive(:inside!).ordered
|
46
|
-
expect(behavior).to receive(:after!).ordered
|
47
|
-
lifecycle.run_callbacks :execute, *arguments, &wrapped_block
|
48
|
-
end
|
49
|
-
|
50
|
-
it 'executes multiple callbacks in order' do
|
51
|
-
expect(behavior).to receive(:one).ordered
|
52
|
-
expect(behavior).to receive(:two).ordered
|
53
|
-
expect(behavior).to receive(:three).ordered
|
54
|
-
|
55
|
-
lifecycle.around(:execute) do |*args, &block|
|
56
|
-
behavior.one
|
57
|
-
block.call(*args)
|
58
|
-
end
|
59
|
-
lifecycle.around(:execute) do |*args, &block|
|
60
|
-
behavior.two
|
61
|
-
block.call(*args)
|
62
|
-
end
|
63
|
-
lifecycle.around(:execute) do |*args, &block|
|
64
|
-
behavior.three
|
65
|
-
block.call(*args)
|
66
|
-
end
|
67
|
-
lifecycle.run_callbacks(:execute, *arguments, &wrapped_block)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
it 'raises if callback is executed with wrong number of parameters' do
|
72
|
-
lifecycle.before(:execute, &callback)
|
73
|
-
expect { lifecycle.run_callbacks(:execute, 1, 2, 3) {} }.to raise_error(ArgumentError, /1 parameter/)
|
74
|
-
end
|
75
|
-
end
|
@@ -1,122 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
describe Delayed::MessageSending do
|
4
|
-
describe 'handle_asynchronously' do
|
5
|
-
class Story
|
6
|
-
def tell!(_arg); end
|
7
|
-
handle_asynchronously :tell!
|
8
|
-
end
|
9
|
-
|
10
|
-
it 'aliases original method' do
|
11
|
-
expect(Story.new).to respond_to(:tell_without_delay!)
|
12
|
-
expect(Story.new).to respond_to(:tell_with_delay!)
|
13
|
-
end
|
14
|
-
|
15
|
-
it 'creates a PerformableMethod' do
|
16
|
-
story = Story.create
|
17
|
-
expect do
|
18
|
-
job = story.tell!(1)
|
19
|
-
expect(job.payload_object.class).to eq(Delayed::PerformableMethod)
|
20
|
-
expect(job.payload_object.method_name).to eq(:tell_without_delay!)
|
21
|
-
expect(job.payload_object.args).to eq([1])
|
22
|
-
end.to change { Delayed::Job.count }
|
23
|
-
end
|
24
|
-
|
25
|
-
describe 'with options' do
|
26
|
-
class Fable
|
27
|
-
cattr_accessor :importance
|
28
|
-
def tell; end
|
29
|
-
handle_asynchronously :tell, :priority => proc { importance }
|
30
|
-
end
|
31
|
-
|
32
|
-
it 'sets the priority based on the Fable importance' do
|
33
|
-
Fable.importance = 10
|
34
|
-
job = Fable.new.tell
|
35
|
-
expect(job.priority).to eq(10)
|
36
|
-
|
37
|
-
Fable.importance = 20
|
38
|
-
job = Fable.new.tell
|
39
|
-
expect(job.priority).to eq(20)
|
40
|
-
end
|
41
|
-
|
42
|
-
describe 'using a proc with parameters' do
|
43
|
-
class Yarn
|
44
|
-
attr_accessor :importance
|
45
|
-
def spin
|
46
|
-
end
|
47
|
-
handle_asynchronously :spin, :priority => proc { |y| y.importance }
|
48
|
-
end
|
49
|
-
|
50
|
-
it 'sets the priority based on the Fable importance' do
|
51
|
-
job = Yarn.new.tap { |y| y.importance = 10 }.spin
|
52
|
-
expect(job.priority).to eq(10)
|
53
|
-
|
54
|
-
job = Yarn.new.tap { |y| y.importance = 20 }.spin
|
55
|
-
expect(job.priority).to eq(20)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
context 'delay' do
|
62
|
-
class FairyTail
|
63
|
-
attr_accessor :happy_ending
|
64
|
-
def self.princesses; end
|
65
|
-
def tell
|
66
|
-
@happy_ending = true
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
after do
|
71
|
-
Delayed::Worker.default_queue_name = nil
|
72
|
-
end
|
73
|
-
|
74
|
-
it 'creates a new PerformableMethod job' do
|
75
|
-
expect do
|
76
|
-
job = 'hello'.delay.count('l')
|
77
|
-
expect(job.payload_object.class).to eq(Delayed::PerformableMethod)
|
78
|
-
expect(job.payload_object.method_name).to eq(:count)
|
79
|
-
expect(job.payload_object.args).to eq(['l'])
|
80
|
-
end.to change { Delayed::Job.count }.by(1)
|
81
|
-
end
|
82
|
-
|
83
|
-
it 'sets default priority' do
|
84
|
-
Delayed::Worker.default_priority = 99
|
85
|
-
job = FairyTail.delay.to_s
|
86
|
-
expect(job.priority).to eq(99)
|
87
|
-
end
|
88
|
-
|
89
|
-
it 'sets default queue name' do
|
90
|
-
Delayed::Worker.default_queue_name = 'abbazabba'
|
91
|
-
job = FairyTail.delay.to_s
|
92
|
-
expect(job.queue).to eq('abbazabba')
|
93
|
-
end
|
94
|
-
|
95
|
-
it 'sets job options' do
|
96
|
-
run_at = Time.parse('2010-05-03 12:55 AM')
|
97
|
-
job = FairyTail.delay(:priority => 20, :run_at => run_at).to_s
|
98
|
-
expect(job.run_at).to eq(run_at)
|
99
|
-
expect(job.priority).to eq(20)
|
100
|
-
end
|
101
|
-
|
102
|
-
it 'does not delay the job when delay_jobs is false' do
|
103
|
-
Delayed::Worker.delay_jobs = false
|
104
|
-
fairy_tail = FairyTail.new
|
105
|
-
expect do
|
106
|
-
expect do
|
107
|
-
fairy_tail.delay.tell
|
108
|
-
end.to change(fairy_tail, :happy_ending).from(nil).to(true)
|
109
|
-
end.not_to change { Delayed::Job.count }
|
110
|
-
end
|
111
|
-
|
112
|
-
it 'does delay the job when delay_jobs is true' do
|
113
|
-
Delayed::Worker.delay_jobs = true
|
114
|
-
fairy_tail = FairyTail.new
|
115
|
-
expect do
|
116
|
-
expect do
|
117
|
-
fairy_tail.delay.tell
|
118
|
-
end.not_to change(fairy_tail, :happy_ending)
|
119
|
-
end.to change { Delayed::Job.count }.by(1)
|
120
|
-
end
|
121
|
-
end
|
122
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
require 'action_mailer'
|
4
|
-
class MyMailer < ActionMailer::Base
|
5
|
-
def signup(email)
|
6
|
-
mail :to => email, :subject => 'Delaying Emails', :from => 'delayedjob@example.com', :body => 'Delaying Emails Body'
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
describe ActionMailer::Base do
|
11
|
-
describe 'delay' do
|
12
|
-
it 'enqueues a PerformableEmail job' do
|
13
|
-
expect do
|
14
|
-
job = MyMailer.delay.signup('john@example.com')
|
15
|
-
expect(job.payload_object.class).to eq(Delayed::PerformableMailer)
|
16
|
-
expect(job.payload_object.method_name).to eq(:signup)
|
17
|
-
expect(job.payload_object.args).to eq(['john@example.com'])
|
18
|
-
end.to change { Delayed::Job.count }.by(1)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
describe 'delay on a mail object' do
|
23
|
-
it 'raises an exception' do
|
24
|
-
expect do
|
25
|
-
MyMailer.signup('john@example.com').delay
|
26
|
-
end.to raise_error(RuntimeError)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
describe Delayed::PerformableMailer do
|
31
|
-
describe 'perform' do
|
32
|
-
it 'calls the method and #deliver on the mailer' do
|
33
|
-
email = double('email', :deliver => true)
|
34
|
-
mailer_class = double('MailerClass', :signup => email)
|
35
|
-
mailer = Delayed::PerformableMailer.new(mailer_class, :signup, ['john@example.com'])
|
36
|
-
|
37
|
-
expect(mailer_class).to receive(:signup).with('john@example.com')
|
38
|
-
expect(email).to receive(:deliver)
|
39
|
-
mailer.perform
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
end
|
@@ -1,144 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
describe Delayed::PerformableMethod do
|
4
|
-
describe 'perform' do
|
5
|
-
before do
|
6
|
-
@method = Delayed::PerformableMethod.new('foo', :count, ['o'])
|
7
|
-
end
|
8
|
-
|
9
|
-
context 'with the persisted record cannot be found' do
|
10
|
-
before do
|
11
|
-
@method.object = nil
|
12
|
-
end
|
13
|
-
|
14
|
-
it 'does nothing if object is nil' do
|
15
|
-
expect { @method.perform }.not_to raise_error
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
it 'calls the method on the object' do
|
20
|
-
expect(@method.object).to receive(:count).with('o')
|
21
|
-
@method.perform
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
it "raises a NoMethodError if target method doesn't exist" do
|
26
|
-
expect do
|
27
|
-
Delayed::PerformableMethod.new(Object, :method_that_does_not_exist, [])
|
28
|
-
end.to raise_error(NoMethodError)
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'does not raise NoMethodError if target method is private' do
|
32
|
-
clazz = Class.new do
|
33
|
-
def private_method
|
34
|
-
end
|
35
|
-
private :private_method
|
36
|
-
end
|
37
|
-
expect { Delayed::PerformableMethod.new(clazz.new, :private_method, []) }.not_to raise_error
|
38
|
-
end
|
39
|
-
|
40
|
-
describe 'display_name' do
|
41
|
-
it 'returns class_name#method_name for instance methods' do
|
42
|
-
expect(Delayed::PerformableMethod.new('foo', :count, ['o']).display_name).to eq('String#count')
|
43
|
-
end
|
44
|
-
|
45
|
-
it 'returns class_name.method_name for class methods' do
|
46
|
-
expect(Delayed::PerformableMethod.new(Class, :inspect, []).display_name).to eq('Class.inspect')
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
describe 'hooks' do
|
51
|
-
%w[before after success].each do |hook|
|
52
|
-
it "delegates #{hook} hook to object" do
|
53
|
-
story = Story.create
|
54
|
-
job = story.delay.tell
|
55
|
-
|
56
|
-
expect(story).to receive(hook).with(job)
|
57
|
-
job.invoke_job
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
%w[before after success].each do |hook|
|
62
|
-
it "delegates #{hook} hook to object" do
|
63
|
-
story = Story.create
|
64
|
-
job = story.delay.tell
|
65
|
-
|
66
|
-
expect(story).to receive(hook).with(job)
|
67
|
-
job.invoke_job
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
it 'delegates enqueue hook to object' do
|
72
|
-
story = Story.create
|
73
|
-
expect(story).to receive(:enqueue).with(an_instance_of(Delayed::Job))
|
74
|
-
story.delay.tell
|
75
|
-
end
|
76
|
-
|
77
|
-
it 'delegates error hook to object' do
|
78
|
-
story = Story.create
|
79
|
-
expect(story).to receive(:error).with(an_instance_of(Delayed::Job), an_instance_of(RuntimeError))
|
80
|
-
expect(story).to receive(:tell).and_raise(RuntimeError)
|
81
|
-
expect { story.delay.tell.invoke_job }.to raise_error
|
82
|
-
end
|
83
|
-
|
84
|
-
it 'delegates error hook to object when delay_jobs = false' do
|
85
|
-
story = Story.create
|
86
|
-
expect(story).to receive(:error).with(an_instance_of(Delayed::Job), an_instance_of(RuntimeError))
|
87
|
-
expect(story).to receive(:tell).and_raise(RuntimeError)
|
88
|
-
expect { story.delay.tell.invoke_job }.to raise_error
|
89
|
-
end
|
90
|
-
|
91
|
-
it 'delegates failure hook to object' do
|
92
|
-
method = Delayed::PerformableMethod.new('object', :size, [])
|
93
|
-
expect(method.object).to receive(:failure)
|
94
|
-
method.failure
|
95
|
-
end
|
96
|
-
|
97
|
-
context 'with delay_job == false' do
|
98
|
-
before do
|
99
|
-
Delayed::Worker.delay_jobs = false
|
100
|
-
end
|
101
|
-
|
102
|
-
after do
|
103
|
-
Delayed::Worker.delay_jobs = true
|
104
|
-
end
|
105
|
-
|
106
|
-
%w[before after success].each do |hook|
|
107
|
-
it "delegates #{hook} hook to object" do
|
108
|
-
story = Story.create
|
109
|
-
expect(story).to receive(hook).with(an_instance_of(Delayed::Job))
|
110
|
-
story.delay.tell
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
%w[before after success].each do |hook|
|
115
|
-
it "delegates #{hook} hook to object" do
|
116
|
-
story = Story.create
|
117
|
-
expect(story).to receive(hook).with(an_instance_of(Delayed::Job))
|
118
|
-
story.delay.tell
|
119
|
-
end
|
120
|
-
end
|
121
|
-
|
122
|
-
it 'delegates error hook to object' do
|
123
|
-
story = Story.create
|
124
|
-
expect(story).to receive(:error).with(an_instance_of(Delayed::Job), an_instance_of(RuntimeError))
|
125
|
-
expect(story).to receive(:tell).and_raise(RuntimeError)
|
126
|
-
expect { story.delay.tell }.to raise_error
|
127
|
-
end
|
128
|
-
|
129
|
-
it 'delegates error hook to object when delay_jobs = false' do
|
130
|
-
story = Story.create
|
131
|
-
expect(story).to receive(:error).with(an_instance_of(Delayed::Job), an_instance_of(RuntimeError))
|
132
|
-
expect(story).to receive(:tell).and_raise(RuntimeError)
|
133
|
-
expect { story.delay.tell }.to raise_error
|
134
|
-
end
|
135
|
-
|
136
|
-
it 'delegates failure hook to object when delay_jobs = false' do
|
137
|
-
Delayed::Worker.delay_jobs = false
|
138
|
-
method = Delayed::PerformableMethod.new('object', :size, [])
|
139
|
-
expect(method.object).to receive(:failure)
|
140
|
-
method.failure
|
141
|
-
end
|
142
|
-
end
|
143
|
-
end
|
144
|
-
end
|
data/spec/psych_ext_spec.rb
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
describe 'Psych::Visitors::ToRuby', :if => defined?(Psych::Visitors::ToRuby) do
|
4
|
-
context BigDecimal do
|
5
|
-
it 'deserializes correctly' do
|
6
|
-
deserialized = YAML.load("--- !ruby/object:BigDecimal 18:0.1337E2\n...\n")
|
7
|
-
|
8
|
-
expect(deserialized).to be_an_instance_of(BigDecimal)
|
9
|
-
expect(deserialized).to eq(BigDecimal('13.37'))
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
data/spec/sample_jobs.rb
DELETED
@@ -1,109 +0,0 @@
|
|
1
|
-
class NamedJob < Struct.new(:perform)
|
2
|
-
def display_name
|
3
|
-
'named_job'
|
4
|
-
end
|
5
|
-
end
|
6
|
-
|
7
|
-
class SimpleJob
|
8
|
-
cattr_accessor :runs
|
9
|
-
@runs = 0
|
10
|
-
def perform
|
11
|
-
self.class.runs += 1
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
class NamedQueueJob < SimpleJob
|
16
|
-
def queue_name
|
17
|
-
'job_tracking'
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
class ErrorJob
|
22
|
-
cattr_accessor :runs
|
23
|
-
@runs = 0
|
24
|
-
def perform
|
25
|
-
raise 'did not work'
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
class CustomRescheduleJob < Struct.new(:offset)
|
30
|
-
cattr_accessor :runs
|
31
|
-
@runs = 0
|
32
|
-
def perform
|
33
|
-
raise 'did not work'
|
34
|
-
end
|
35
|
-
|
36
|
-
def reschedule_at(time, _attempts)
|
37
|
-
time + offset
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
class LongRunningJob
|
42
|
-
def perform
|
43
|
-
sleep 250
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
class OnPermanentFailureJob < SimpleJob
|
48
|
-
attr_writer :raise_error
|
49
|
-
|
50
|
-
def initialize
|
51
|
-
@raise_error = false
|
52
|
-
end
|
53
|
-
|
54
|
-
def failure
|
55
|
-
raise 'did not work' if @raise_error
|
56
|
-
end
|
57
|
-
|
58
|
-
def max_attempts
|
59
|
-
1
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
module M
|
64
|
-
class ModuleJob
|
65
|
-
cattr_accessor :runs
|
66
|
-
@runs = 0
|
67
|
-
def perform
|
68
|
-
self.class.runs += 1
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
class CallbackJob
|
74
|
-
cattr_accessor :messages
|
75
|
-
|
76
|
-
def enqueue(_job)
|
77
|
-
self.class.messages << 'enqueue'
|
78
|
-
end
|
79
|
-
|
80
|
-
def before(_job)
|
81
|
-
self.class.messages << 'before'
|
82
|
-
end
|
83
|
-
|
84
|
-
def perform
|
85
|
-
self.class.messages << 'perform'
|
86
|
-
end
|
87
|
-
|
88
|
-
def after(_job)
|
89
|
-
self.class.messages << 'after'
|
90
|
-
end
|
91
|
-
|
92
|
-
def success(_job)
|
93
|
-
self.class.messages << 'success'
|
94
|
-
end
|
95
|
-
|
96
|
-
def error(_job, error)
|
97
|
-
self.class.messages << "error: #{error.class}"
|
98
|
-
end
|
99
|
-
|
100
|
-
def failure(_job)
|
101
|
-
self.class.messages << 'failure'
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
class EnqueueJobMod < SimpleJob
|
106
|
-
def enqueue(job)
|
107
|
-
job.run_at = 20.minutes.from_now
|
108
|
-
end
|
109
|
-
end
|
data/spec/test_backend_spec.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
describe Delayed::Backend::Test::Job do
|
4
|
-
it_should_behave_like 'a delayed_job backend'
|
5
|
-
|
6
|
-
describe '#reload' do
|
7
|
-
it 'causes the payload object to be reloaded' do
|
8
|
-
job = 'foo'.delay.length
|
9
|
-
o = job.payload_object
|
10
|
-
expect(o.object_id).not_to eq(job.reload.payload_object.object_id)
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
data/spec/worker_spec.rb
DELETED
@@ -1,157 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
describe Delayed::Worker do
|
4
|
-
describe 'backend=' do
|
5
|
-
before do
|
6
|
-
@clazz = Class.new
|
7
|
-
Delayed::Worker.backend = @clazz
|
8
|
-
end
|
9
|
-
|
10
|
-
after do
|
11
|
-
Delayed::Worker.backend = :test
|
12
|
-
end
|
13
|
-
|
14
|
-
it 'sets the Delayed::Job constant to the backend' do
|
15
|
-
expect(Delayed::Job).to eq(@clazz)
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'sets backend with a symbol' do
|
19
|
-
Delayed::Worker.backend = :test
|
20
|
-
expect(Delayed::Worker.backend).to eq(Delayed::Backend::Test::Job)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
describe 'job_say' do
|
25
|
-
before do
|
26
|
-
@worker = Delayed::Worker.new
|
27
|
-
@job = double('job', :id => 123, :name => 'ExampleJob')
|
28
|
-
end
|
29
|
-
|
30
|
-
it 'logs with job name and id' do
|
31
|
-
expect(@worker).to receive(:say).
|
32
|
-
with('Job ExampleJob (id=123) message', Delayed::Worker.default_log_level)
|
33
|
-
@worker.job_say(@job, 'message')
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'has a configurable default log level' do
|
37
|
-
Delayed::Worker.default_log_level = 'error'
|
38
|
-
|
39
|
-
expect(@worker).to receive(:say).
|
40
|
-
with('Job ExampleJob (id=123) message', 'error')
|
41
|
-
@worker.job_say(@job, 'message')
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
context 'worker read-ahead' do
|
46
|
-
before do
|
47
|
-
@read_ahead = Delayed::Worker.read_ahead
|
48
|
-
end
|
49
|
-
|
50
|
-
after do
|
51
|
-
Delayed::Worker.read_ahead = @read_ahead
|
52
|
-
end
|
53
|
-
|
54
|
-
it 'reads five jobs' do
|
55
|
-
expect(Delayed::Job).to receive(:find_available).with(anything, 5, anything).and_return([])
|
56
|
-
Delayed::Job.reserve(Delayed::Worker.new)
|
57
|
-
end
|
58
|
-
|
59
|
-
it 'reads a configurable number of jobs' do
|
60
|
-
Delayed::Worker.read_ahead = 15
|
61
|
-
expect(Delayed::Job).to receive(:find_available).with(anything, Delayed::Worker.read_ahead, anything).and_return([])
|
62
|
-
Delayed::Job.reserve(Delayed::Worker.new)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
context 'worker exit on complete' do
|
67
|
-
before do
|
68
|
-
Delayed::Worker.exit_on_complete = true
|
69
|
-
end
|
70
|
-
|
71
|
-
after do
|
72
|
-
Delayed::Worker.exit_on_complete = false
|
73
|
-
end
|
74
|
-
|
75
|
-
it 'exits the loop when no jobs are available' do
|
76
|
-
worker = Delayed::Worker.new
|
77
|
-
Timeout.timeout(2) do
|
78
|
-
worker.start
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
context 'worker job reservation' do
|
84
|
-
before do
|
85
|
-
Delayed::Worker.exit_on_complete = true
|
86
|
-
end
|
87
|
-
|
88
|
-
after do
|
89
|
-
Delayed::Worker.exit_on_complete = false
|
90
|
-
end
|
91
|
-
|
92
|
-
it 'handles error during job reservation' do
|
93
|
-
expect(Delayed::Job).to receive(:reserve).and_raise(Exception)
|
94
|
-
Delayed::Worker.new.work_off
|
95
|
-
end
|
96
|
-
|
97
|
-
it 'gives up after 10 backend failures' do
|
98
|
-
expect(Delayed::Job).to receive(:reserve).exactly(10).times.and_raise(Exception)
|
99
|
-
worker = Delayed::Worker.new
|
100
|
-
9.times { worker.work_off }
|
101
|
-
expect(lambda { worker.work_off }).to raise_exception Delayed::FatalBackendError
|
102
|
-
end
|
103
|
-
|
104
|
-
it 'allows the backend to attempt recovery from reservation errors' do
|
105
|
-
expect(Delayed::Job).to receive(:reserve).and_raise(Exception)
|
106
|
-
expect(Delayed::Job).to receive(:recover_from).with(instance_of(Exception))
|
107
|
-
Delayed::Worker.new.work_off
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
context '#say' do
|
112
|
-
before(:each) do
|
113
|
-
@worker = Delayed::Worker.new
|
114
|
-
@worker.name = 'ExampleJob'
|
115
|
-
@worker.logger = double('job')
|
116
|
-
time = Time.now
|
117
|
-
allow(Time).to receive(:now).and_return(time)
|
118
|
-
@text = 'Job executed'
|
119
|
-
@worker_name = '[Worker(ExampleJob)]'
|
120
|
-
@expected_time = time.strftime('%FT%T%z')
|
121
|
-
end
|
122
|
-
|
123
|
-
after(:each) do
|
124
|
-
@worker.logger = nil
|
125
|
-
end
|
126
|
-
|
127
|
-
shared_examples_for 'a worker which logs on the correct severity' do |severity|
|
128
|
-
it "logs a message on the #{severity[:level].upcase} level given a string" do
|
129
|
-
expect(@worker.logger).to receive(:send).
|
130
|
-
with(severity[:level], "#{@expected_time}: #{@worker_name} #{@text}")
|
131
|
-
@worker.say(@text, severity[:level])
|
132
|
-
end
|
133
|
-
|
134
|
-
it "logs a message on the #{severity[:level].upcase} level given a fixnum" do
|
135
|
-
expect(@worker.logger).to receive(:send).
|
136
|
-
with(severity[:level], "#{@expected_time}: #{@worker_name} #{@text}")
|
137
|
-
@worker.say(@text, severity[:index])
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
severities = [{:index => 0, :level => 'debug'},
|
142
|
-
{:index => 1, :level => 'info'},
|
143
|
-
{:index => 2, :level => 'warn'},
|
144
|
-
{:index => 3, :level => 'error'},
|
145
|
-
{:index => 4, :level => 'fatal'},
|
146
|
-
{:index => 5, :level => 'unknown'}]
|
147
|
-
severities.each do |severity|
|
148
|
-
it_behaves_like 'a worker which logs on the correct severity', severity
|
149
|
-
end
|
150
|
-
|
151
|
-
it 'logs a message on the default log\'s level' do
|
152
|
-
expect(@worker.logger).to receive(:send).
|
153
|
-
with('info', "#{@expected_time}: #{@worker_name} #{@text}")
|
154
|
-
@worker.say(@text, Delayed::Worker.default_log_level)
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
data/spec/yaml_ext_spec.rb
DELETED
@@ -1,48 +0,0 @@
|
|
1
|
-
require 'helper'
|
2
|
-
|
3
|
-
describe 'YAML' do
|
4
|
-
it 'autoloads classes' do
|
5
|
-
expect do
|
6
|
-
yaml = "--- !ruby/class Autoloaded::Clazz\n"
|
7
|
-
expect(load_with_delayed_visitor(yaml)).to eq(Autoloaded::Clazz)
|
8
|
-
end.not_to raise_error
|
9
|
-
end
|
10
|
-
|
11
|
-
it 'autoloads the class of a struct' do
|
12
|
-
expect do
|
13
|
-
yaml = "--- !ruby/class Autoloaded::Struct\n"
|
14
|
-
expect(load_with_delayed_visitor(yaml)).to eq(Autoloaded::Struct)
|
15
|
-
end.not_to raise_error
|
16
|
-
end
|
17
|
-
|
18
|
-
it 'autoloads the class for the instance of a struct' do
|
19
|
-
expect do
|
20
|
-
yaml = '--- !ruby/struct:Autoloaded::InstanceStruct {}'
|
21
|
-
expect(load_with_delayed_visitor(yaml).class).to eq(Autoloaded::InstanceStruct)
|
22
|
-
end.not_to raise_error
|
23
|
-
end
|
24
|
-
|
25
|
-
it 'autoloads the class of an anonymous struct' do
|
26
|
-
expect do
|
27
|
-
yaml = "--- !ruby/struct\nn: 1\n"
|
28
|
-
object = YAML.load(yaml)
|
29
|
-
expect(object).to be_kind_of(Struct)
|
30
|
-
expect(object.n).to eq(1)
|
31
|
-
end.not_to raise_error
|
32
|
-
end
|
33
|
-
|
34
|
-
it 'autoloads the class for the instance' do
|
35
|
-
expect do
|
36
|
-
yaml = "--- !ruby/object:Autoloaded::InstanceClazz {}\n"
|
37
|
-
expect(load_with_delayed_visitor(yaml).class).to eq(Autoloaded::InstanceClazz)
|
38
|
-
end.not_to raise_error
|
39
|
-
end
|
40
|
-
|
41
|
-
it 'does not throw an uninitialized constant Syck::Syck when using YAML.load with poorly formed yaml' do
|
42
|
-
expect { YAML.load(YAML.dump('foo: *bar')) }.not_to raise_error
|
43
|
-
end
|
44
|
-
|
45
|
-
def load_with_delayed_visitor(yaml)
|
46
|
-
YAML.load_dj(yaml)
|
47
|
-
end
|
48
|
-
end
|