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