delayed_job 4.0.6 → 4.1.8
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 +5 -5
- data/CHANGELOG.md +54 -0
- data/README.md +89 -15
- data/delayed_job.gemspec +5 -3
- data/lib/delayed/backend/base.rb +26 -32
- data/lib/delayed/backend/job_preparer.rb +53 -0
- data/lib/delayed/backend/shared_spec.rb +92 -10
- data/lib/delayed/command.rb +40 -14
- data/lib/delayed/exceptions.rb +1 -1
- data/lib/delayed/lifecycle.rb +2 -2
- data/lib/delayed/message_sending.rb +29 -17
- data/lib/delayed/performable_method.rb +6 -4
- data/lib/delayed/psych_ext.rb +20 -7
- data/lib/delayed/railtie.rb +0 -4
- data/lib/delayed/recipes.rb +3 -3
- data/lib/delayed/serialization/active_record.rb +1 -1
- data/lib/delayed/syck_ext.rb +3 -3
- data/lib/delayed/tasks.rb +1 -1
- data/lib/delayed/worker.rb +62 -24
- data/lib/delayed_job.rb +11 -7
- data/lib/generators/delayed_job/delayed_job_generator.rb +1 -1
- data/spec/autoloaded/clazz.rb +1 -2
- data/spec/autoloaded/instance_clazz.rb +1 -2
- data/spec/autoloaded/instance_struct.rb +3 -3
- data/spec/autoloaded/struct.rb +3 -3
- data/spec/daemons.rb +2 -0
- data/spec/delayed/backend/test.rb +0 -5
- data/spec/delayed/command_spec.rb +131 -9
- data/spec/helper.rb +0 -4
- data/spec/message_sending_spec.rb +29 -4
- data/spec/performable_mailer_spec.rb +0 -1
- data/spec/performable_method_spec.rb +3 -4
- data/spec/psych_ext_spec.rb +23 -1
- data/spec/sample_jobs.rb +5 -3
- data/spec/worker_spec.rb +27 -1
- metadata +17 -15
data/lib/delayed_job.rb
CHANGED
@@ -3,20 +3,24 @@ require 'delayed/compatibility'
|
|
3
3
|
require 'delayed/exceptions'
|
4
4
|
require 'delayed/message_sending'
|
5
5
|
require 'delayed/performable_method'
|
6
|
-
|
7
|
-
if defined?(ActionMailer)
|
8
|
-
require 'action_mailer/version'
|
9
|
-
require 'delayed/performable_mailer'
|
10
|
-
end
|
11
|
-
|
12
6
|
require 'delayed/yaml_ext'
|
13
7
|
require 'delayed/lifecycle'
|
14
8
|
require 'delayed/plugin'
|
15
9
|
require 'delayed/plugins/clear_locks'
|
16
10
|
require 'delayed/backend/base'
|
11
|
+
require 'delayed/backend/job_preparer'
|
17
12
|
require 'delayed/worker'
|
18
13
|
require 'delayed/deserialization_error'
|
19
14
|
require 'delayed/railtie' if defined?(Rails::Railtie)
|
20
15
|
|
16
|
+
ActiveSupport.on_load(:action_mailer) do
|
17
|
+
require 'delayed/performable_mailer'
|
18
|
+
ActionMailer::Base.extend(Delayed::DelayMail)
|
19
|
+
end
|
20
|
+
|
21
|
+
module Delayed
|
22
|
+
autoload :PerformableMailer, 'delayed/performable_mailer'
|
23
|
+
end
|
24
|
+
|
21
25
|
Object.send(:include, Delayed::MessageSending)
|
22
|
-
Module.send(:include, Delayed::
|
26
|
+
Module.send(:include, Delayed::MessageSendingClassMethods)
|
@@ -6,6 +6,6 @@ class DelayedJobGenerator < Rails::Generators::Base
|
|
6
6
|
|
7
7
|
def create_executable_file
|
8
8
|
template 'script', "#{Delayed::Compatibility.executable_prefix}/delayed_job"
|
9
|
-
chmod "#{Delayed::Compatibility.executable_prefix}/delayed_job",
|
9
|
+
chmod "#{Delayed::Compatibility.executable_prefix}/delayed_job", 0o755
|
10
10
|
end
|
11
11
|
end
|
data/spec/autoloaded/clazz.rb
CHANGED
data/spec/autoloaded/struct.rb
CHANGED
data/spec/daemons.rb
ADDED
@@ -2,6 +2,129 @@ require 'helper'
|
|
2
2
|
require 'delayed/command'
|
3
3
|
|
4
4
|
describe Delayed::Command do
|
5
|
+
let(:options) { [] }
|
6
|
+
let(:logger) { double('Logger') }
|
7
|
+
|
8
|
+
subject { Delayed::Command.new options }
|
9
|
+
|
10
|
+
before do
|
11
|
+
allow(Delayed::Worker).to receive(:after_fork)
|
12
|
+
allow(Dir).to receive(:chdir)
|
13
|
+
allow(Logger).to receive(:new).and_return(logger)
|
14
|
+
allow_any_instance_of(Delayed::Worker).to receive(:start)
|
15
|
+
allow(Delayed::Worker).to receive(:logger=)
|
16
|
+
allow(Delayed::Worker).to receive(:logger).and_return(nil, logger)
|
17
|
+
end
|
18
|
+
|
19
|
+
shared_examples_for 'uses --log-dir option' do
|
20
|
+
context 'when --log-dir is specified' do
|
21
|
+
let(:options) { ['--log-dir=/custom/log/dir'] }
|
22
|
+
|
23
|
+
it 'creates the delayed_job.log in the specified directory' do
|
24
|
+
expect(Logger).to receive(:new).with('/custom/log/dir/delayed_job.log')
|
25
|
+
subject.run
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe 'run' do
|
31
|
+
it 'sets the Delayed::Worker logger' do
|
32
|
+
expect(Delayed::Worker).to receive(:logger=).with(logger)
|
33
|
+
subject.run
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when Rails root is defined' do
|
37
|
+
let(:rails_root) { Pathname.new '/rails/root' }
|
38
|
+
let(:rails) { double('Rails', :root => rails_root) }
|
39
|
+
|
40
|
+
before do
|
41
|
+
stub_const('Rails', rails)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'runs the Delayed::Worker process in Rails.root' do
|
45
|
+
expect(Dir).to receive(:chdir).with(rails_root)
|
46
|
+
subject.run
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'when --log-dir is not specified' do
|
50
|
+
it 'creates the delayed_job.log in Rails.root/log' do
|
51
|
+
expect(Logger).to receive(:new).with('/rails/root/log/delayed_job.log')
|
52
|
+
subject.run
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
include_examples 'uses --log-dir option'
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'when Rails root is not defined' do
|
60
|
+
let(:rails_without_root) { double('Rails') }
|
61
|
+
|
62
|
+
before do
|
63
|
+
stub_const('Rails', rails_without_root)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'runs the Delayed::Worker process in $PWD' do
|
67
|
+
expect(Dir).to receive(:chdir).with(Delayed::Command::DIR_PWD)
|
68
|
+
subject.run
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'when --log-dir is not specified' do
|
72
|
+
it 'creates the delayed_job.log in $PWD/log' do
|
73
|
+
expect(Logger).to receive(:new).with("#{Delayed::Command::DIR_PWD}/log/delayed_job.log")
|
74
|
+
subject.run
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
include_examples 'uses --log-dir option'
|
79
|
+
end
|
80
|
+
|
81
|
+
context 'when an error is raised' do
|
82
|
+
let(:test_error) { Class.new(StandardError) }
|
83
|
+
|
84
|
+
before do
|
85
|
+
allow(Delayed::Worker).to receive(:new).and_raise(test_error.new('An error'))
|
86
|
+
allow(subject).to receive(:exit_with_error_status)
|
87
|
+
allow(STDERR).to receive(:puts)
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'prints the error message to STDERR' do
|
91
|
+
expect(STDERR).to receive(:puts).with('An error')
|
92
|
+
subject.run
|
93
|
+
end
|
94
|
+
|
95
|
+
it 'exits with an error status' do
|
96
|
+
expect(subject).to receive(:exit_with_error_status)
|
97
|
+
subject.run
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'when Rails logger is not defined' do
|
101
|
+
let(:rails) { double('Rails') }
|
102
|
+
|
103
|
+
before do
|
104
|
+
stub_const('Rails', rails)
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'does not attempt to use the Rails logger' do
|
108
|
+
subject.run
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context 'when Rails logger is defined' do
|
113
|
+
let(:rails_logger) { double('Rails logger') }
|
114
|
+
let(:rails) { double('Rails', :logger => rails_logger) }
|
115
|
+
|
116
|
+
before do
|
117
|
+
stub_const('Rails', rails)
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'logs the error to the Rails logger' do
|
121
|
+
expect(rails_logger).to receive(:fatal).with(test_error)
|
122
|
+
subject.run
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
5
128
|
describe 'parsing --pool argument' do
|
6
129
|
it 'should parse --pool correctly' do
|
7
130
|
command = Delayed::Command.new(['--pool=*:1', '--pool=test_queue:4', '--pool=mailers,misc:2'])
|
@@ -36,17 +159,16 @@ describe Delayed::Command do
|
|
36
159
|
describe 'running worker pools defined by multiple --pool arguments' do
|
37
160
|
it 'should run the correct worker processes' do
|
38
161
|
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
|
162
|
+
expect(FileUtils).to receive(:mkdir_p).with('./tmp/pids').once
|
41
163
|
|
42
164
|
[
|
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]}]
|
165
|
+
['delayed_job.0', {:quiet => true, :pid_dir => './tmp/pids', :log_dir => './log', :queues => []}],
|
166
|
+
['delayed_job.1', {:quiet => true, :pid_dir => './tmp/pids', :log_dir => './log', :queues => ['test_queue']}],
|
167
|
+
['delayed_job.2', {:quiet => true, :pid_dir => './tmp/pids', :log_dir => './log', :queues => ['test_queue']}],
|
168
|
+
['delayed_job.3', {:quiet => true, :pid_dir => './tmp/pids', :log_dir => './log', :queues => ['test_queue']}],
|
169
|
+
['delayed_job.4', {:quiet => true, :pid_dir => './tmp/pids', :log_dir => './log', :queues => ['test_queue']}],
|
170
|
+
['delayed_job.5', {:quiet => true, :pid_dir => './tmp/pids', :log_dir => './log', :queues => %w[mailers misc]}],
|
171
|
+
['delayed_job.6', {:quiet => true, :pid_dir => './tmp/pids', :log_dir => './log', :queues => %w[mailers misc]}]
|
50
172
|
].each do |args|
|
51
173
|
expect(command).to receive(:run_process).with(*args).once
|
52
174
|
end
|
data/spec/helper.rb
CHANGED
@@ -14,7 +14,6 @@ require 'logger'
|
|
14
14
|
require 'rspec'
|
15
15
|
|
16
16
|
require 'action_mailer'
|
17
|
-
require 'active_support/dependencies'
|
18
17
|
require 'active_record'
|
19
18
|
|
20
19
|
require 'delayed_job'
|
@@ -45,9 +44,6 @@ Delayed::Worker.backend = :test
|
|
45
44
|
# Add this directory so the ActiveSupport autoloading works
|
46
45
|
ActiveSupport::Dependencies.autoload_paths << File.dirname(__FILE__)
|
47
46
|
|
48
|
-
# Add this to simulate Railtie initializer being executed
|
49
|
-
ActionMailer::Base.extend(Delayed::DelayMail)
|
50
|
-
|
51
47
|
# Used to test interactions between DJ and an ORM
|
52
48
|
ActiveRecord::Base.establish_connection :adapter => 'sqlite3', :database => ':memory:'
|
53
49
|
ActiveRecord::Base.logger = Delayed::Worker.logger
|
@@ -1,6 +1,11 @@
|
|
1
1
|
require 'helper'
|
2
2
|
|
3
3
|
describe Delayed::MessageSending do
|
4
|
+
it 'does not include ClassMethods along with MessageSending' do
|
5
|
+
expect { ClassMethods }.to raise_error(NameError)
|
6
|
+
expect(defined?(String::ClassMethods)).to eq(nil)
|
7
|
+
end
|
8
|
+
|
4
9
|
describe 'handle_asynchronously' do
|
5
10
|
class Story
|
6
11
|
def tell!(_arg); end
|
@@ -19,7 +24,7 @@ describe Delayed::MessageSending do
|
|
19
24
|
expect(job.payload_object.class).to eq(Delayed::PerformableMethod)
|
20
25
|
expect(job.payload_object.method_name).to eq(:tell_without_delay!)
|
21
26
|
expect(job.payload_object.args).to eq([1])
|
22
|
-
end.to
|
27
|
+
end.to(change { Delayed::Job.count })
|
23
28
|
end
|
24
29
|
|
25
30
|
describe 'with options' do
|
@@ -42,8 +47,7 @@ describe Delayed::MessageSending do
|
|
42
47
|
describe 'using a proc with parameters' do
|
43
48
|
class Yarn
|
44
49
|
attr_accessor :importance
|
45
|
-
def spin
|
46
|
-
end
|
50
|
+
def spin; end
|
47
51
|
handle_asynchronously :spin, :priority => proc { |y| y.importance }
|
48
52
|
end
|
49
53
|
|
@@ -62,6 +66,7 @@ describe Delayed::MessageSending do
|
|
62
66
|
class FairyTail
|
63
67
|
attr_accessor :happy_ending
|
64
68
|
def self.princesses; end
|
69
|
+
|
65
70
|
def tell
|
66
71
|
@happy_ending = true
|
67
72
|
end
|
@@ -106,7 +111,7 @@ describe Delayed::MessageSending do
|
|
106
111
|
expect do
|
107
112
|
fairy_tail.delay.tell
|
108
113
|
end.to change(fairy_tail, :happy_ending).from(nil).to(true)
|
109
|
-
end.not_to
|
114
|
+
end.not_to(change { Delayed::Job.count })
|
110
115
|
end
|
111
116
|
|
112
117
|
it 'does delay the job when delay_jobs is true' do
|
@@ -118,5 +123,25 @@ describe Delayed::MessageSending do
|
|
118
123
|
end.not_to change(fairy_tail, :happy_ending)
|
119
124
|
end.to change { Delayed::Job.count }.by(1)
|
120
125
|
end
|
126
|
+
|
127
|
+
it 'does delay when delay_jobs is a proc returning true' do
|
128
|
+
Delayed::Worker.delay_jobs = ->(_job) { true }
|
129
|
+
fairy_tail = FairyTail.new
|
130
|
+
expect do
|
131
|
+
expect do
|
132
|
+
fairy_tail.delay.tell
|
133
|
+
end.not_to change(fairy_tail, :happy_ending)
|
134
|
+
end.to change { Delayed::Job.count }.by(1)
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'does not delay the job when delay_jobs is a proc returning false' do
|
138
|
+
Delayed::Worker.delay_jobs = ->(_job) { false }
|
139
|
+
fairy_tail = FairyTail.new
|
140
|
+
expect do
|
141
|
+
expect do
|
142
|
+
fairy_tail.delay.tell
|
143
|
+
end.to change(fairy_tail, :happy_ending).from(nil).to(true)
|
144
|
+
end.not_to(change { Delayed::Job.count })
|
145
|
+
end
|
121
146
|
end
|
122
147
|
end
|
@@ -30,8 +30,7 @@ describe Delayed::PerformableMethod do
|
|
30
30
|
|
31
31
|
it 'does not raise NoMethodError if target method is private' do
|
32
32
|
clazz = Class.new do
|
33
|
-
def private_method
|
34
|
-
end
|
33
|
+
def private_method; end
|
35
34
|
private :private_method
|
36
35
|
end
|
37
36
|
expect { Delayed::PerformableMethod.new(clazz.new, :private_method, []) }.not_to raise_error
|
@@ -68,7 +67,7 @@ describe Delayed::PerformableMethod do
|
|
68
67
|
story = Story.create
|
69
68
|
expect(story).to receive(:error).with(an_instance_of(Delayed::Job), an_instance_of(RuntimeError))
|
70
69
|
expect(story).to receive(:tell).and_raise(RuntimeError)
|
71
|
-
expect { story.delay.tell.invoke_job }.to raise_error
|
70
|
+
expect { story.delay.tell.invoke_job }.to raise_error(RuntimeError)
|
72
71
|
end
|
73
72
|
|
74
73
|
it 'delegates failure hook to object' do
|
@@ -98,7 +97,7 @@ describe Delayed::PerformableMethod do
|
|
98
97
|
story = Story.create
|
99
98
|
expect(story).to receive(:error).with(an_instance_of(Delayed::Job), an_instance_of(RuntimeError))
|
100
99
|
expect(story).to receive(:tell).and_raise(RuntimeError)
|
101
|
-
expect { story.delay.tell }.to raise_error
|
100
|
+
expect { story.delay.tell }.to raise_error(RuntimeError)
|
102
101
|
end
|
103
102
|
|
104
103
|
it 'delegates failure hook to object' do
|
data/spec/psych_ext_spec.rb
CHANGED
@@ -3,10 +3,32 @@ require 'helper'
|
|
3
3
|
describe 'Psych::Visitors::ToRuby', :if => defined?(Psych::Visitors::ToRuby) do
|
4
4
|
context BigDecimal do
|
5
5
|
it 'deserializes correctly' do
|
6
|
-
deserialized = YAML.
|
6
|
+
deserialized = YAML.load_dj("--- !ruby/object:BigDecimal 18:0.1337E2\n...\n")
|
7
7
|
|
8
8
|
expect(deserialized).to be_an_instance_of(BigDecimal)
|
9
9
|
expect(deserialized).to eq(BigDecimal('13.37'))
|
10
10
|
end
|
11
11
|
end
|
12
|
+
|
13
|
+
context 'load_tag handling' do
|
14
|
+
# This only broadly works in ruby 2.0 but will cleanly work through load_dj
|
15
|
+
# here because this class is so simple it only touches our extention
|
16
|
+
YAML.load_tags['!ruby/object:RenamedClass'] = SimpleJob
|
17
|
+
# This is how ruby 2.1 and newer works throughout the yaml handling
|
18
|
+
YAML.load_tags['!ruby/object:RenamedString'] = 'SimpleJob'
|
19
|
+
|
20
|
+
it 'deserializes class tag' do
|
21
|
+
deserialized = YAML.load_dj("--- !ruby/object:RenamedClass\ncheck: 12\n")
|
22
|
+
|
23
|
+
expect(deserialized).to be_an_instance_of(SimpleJob)
|
24
|
+
expect(deserialized.instance_variable_get(:@check)).to eq(12)
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'deserializes string tag' do
|
28
|
+
deserialized = YAML.load_dj("--- !ruby/object:RenamedString\ncheck: 12\n")
|
29
|
+
|
30
|
+
expect(deserialized).to be_an_instance_of(SimpleJob)
|
31
|
+
expect(deserialized.instance_variable_get(:@check)).to eq(12)
|
32
|
+
end
|
33
|
+
end
|
12
34
|
end
|
data/spec/sample_jobs.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
|
1
|
+
NamedJob = Struct.new(:perform)
|
2
|
+
class NamedJob
|
2
3
|
def display_name
|
3
4
|
'named_job'
|
4
5
|
end
|
@@ -22,11 +23,12 @@ class ErrorJob
|
|
22
23
|
cattr_accessor :runs
|
23
24
|
@runs = 0
|
24
25
|
def perform
|
25
|
-
raise 'did not work'
|
26
|
+
raise Exception, 'did not work'
|
26
27
|
end
|
27
28
|
end
|
28
29
|
|
29
|
-
|
30
|
+
CustomRescheduleJob = Struct.new(:offset)
|
31
|
+
class CustomRescheduleJob
|
30
32
|
cattr_accessor :runs
|
31
33
|
@runs = 0
|
32
34
|
def perform
|
data/spec/worker_spec.rb
CHANGED
@@ -24,15 +24,23 @@ describe Delayed::Worker do
|
|
24
24
|
describe 'job_say' do
|
25
25
|
before do
|
26
26
|
@worker = Delayed::Worker.new
|
27
|
-
@job = double('job', :id => 123, :name => 'ExampleJob')
|
27
|
+
@job = double('job', :id => 123, :name => 'ExampleJob', :queue => nil)
|
28
28
|
end
|
29
29
|
|
30
30
|
it 'logs with job name and id' do
|
31
|
+
expect(@job).to receive(:queue)
|
31
32
|
expect(@worker).to receive(:say).
|
32
33
|
with('Job ExampleJob (id=123) message', Delayed::Worker.default_log_level)
|
33
34
|
@worker.job_say(@job, 'message')
|
34
35
|
end
|
35
36
|
|
37
|
+
it 'logs with job name, queue and id' do
|
38
|
+
expect(@job).to receive(:queue).and_return('test')
|
39
|
+
expect(@worker).to receive(:say).
|
40
|
+
with('Job ExampleJob (id=123) (queue=test) message', Delayed::Worker.default_log_level)
|
41
|
+
@worker.job_say(@job, 'message')
|
42
|
+
end
|
43
|
+
|
36
44
|
it 'has a configurable default log level' do
|
37
45
|
Delayed::Worker.default_log_level = 'error'
|
38
46
|
|
@@ -154,4 +162,22 @@ describe Delayed::Worker do
|
|
154
162
|
@worker.say(@text, Delayed::Worker.default_log_level)
|
155
163
|
end
|
156
164
|
end
|
165
|
+
|
166
|
+
describe 'plugin registration' do
|
167
|
+
it 'does not double-register plugins on worker instantiation' do
|
168
|
+
performances = 0
|
169
|
+
plugin = Class.new(Delayed::Plugin) do
|
170
|
+
callbacks do |lifecycle|
|
171
|
+
lifecycle.before(:enqueue) { performances += 1 }
|
172
|
+
end
|
173
|
+
end
|
174
|
+
Delayed::Worker.plugins << plugin
|
175
|
+
|
176
|
+
Delayed::Worker.new
|
177
|
+
Delayed::Worker.new
|
178
|
+
Delayed::Worker.lifecycle.run_callbacks(:enqueue, nil) {}
|
179
|
+
|
180
|
+
expect(performances).to eq(1)
|
181
|
+
end
|
182
|
+
end
|
157
183
|
end
|