sisyphus 0.2.3 → 0.2.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 +5 -5
- data/.rspec +2 -0
- data/Gemfile.lock +1 -1
- data/README.md +5 -2
- data/Rakefile +3 -1
- data/lib/sisyphus/forking_execution_strategy.rb +52 -0
- data/lib/sisyphus/master.rb +44 -49
- data/lib/sisyphus/simple_execution_strategy.rb +17 -0
- data/lib/sisyphus/sleep.rb +1 -1
- data/lib/sisyphus/worker.rb +47 -33
- data/lib/sisyphus/worker_pool.rb +36 -0
- data/lib/sisyphus.rb +1 -1
- data/lib/version.rb +1 -1
- data/sisyphus.gemspec +2 -0
- data/spec/sisyphus/forking_execution_strategy_spec.rb +98 -0
- data/spec/sisyphus/master_spec.rb +57 -137
- data/spec/sisyphus/simple_execution_strategy_spec.rb +28 -0
- data/spec/sisyphus/worker_pool_spec.rb +82 -0
- data/spec/sisyphus/worker_spec.rb +84 -82
- data/spec/spec_helper.rb +17 -0
- metadata +25 -17
|
@@ -1,192 +1,112 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
1
2
|
require_relative '../../lib/sisyphus/master'
|
|
2
3
|
|
|
3
4
|
module Sisyphus
|
|
4
5
|
describe Master do
|
|
5
|
-
subject(:master) { Master.new job }
|
|
6
|
+
subject(:master) { Master.new job, worker_pool: worker_pool }
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
let(:worker_pool) { double :worker_pool }
|
|
9
|
+
|
|
10
|
+
before(:each) {
|
|
11
|
+
allow(master).to receive(:puts)
|
|
12
|
+
allow(master).to receive(:sleep)
|
|
13
|
+
}
|
|
8
14
|
|
|
9
15
|
let(:job) { double(:job) }
|
|
10
16
|
let(:pipes) { [double(:reader_pipe), double(:writer_pipe)] }
|
|
11
17
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
before :each do
|
|
22
|
-
master.stub(:fork) { nil }
|
|
23
|
-
IO.stub(:pipe) { pipes }
|
|
24
|
-
pipes.first.stub(:close)
|
|
25
|
-
Process.stub(:pid) { 666 }
|
|
26
|
-
master.stub :exit!
|
|
27
|
-
Worker.stub(:new) { worker }
|
|
28
|
-
worker.stub(:setup)
|
|
29
|
-
worker.stub(:start)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
it 'should setup the worker' do
|
|
33
|
-
worker.should_receive :setup
|
|
34
|
-
master.start_worker
|
|
35
|
-
end
|
|
18
|
+
it 'creates a worker' do
|
|
19
|
+
execution_strategy = double :execution_strategy
|
|
20
|
+
master = Master.new job
|
|
21
|
+
allow(master).to receive(:execution_strategy) { execution_strategy }
|
|
22
|
+
worker = master.create_worker
|
|
23
|
+
expect(worker.job).to eq(job)
|
|
24
|
+
expect(worker.execution_strategy).to eq(execution_strategy)
|
|
25
|
+
end
|
|
36
26
|
|
|
37
|
-
|
|
38
|
-
master.should_receive(:process_name=).with("Worker #{666}")
|
|
39
|
-
master.start_worker
|
|
40
|
-
end
|
|
27
|
+
describe 'when it has running workers' do
|
|
41
28
|
|
|
42
|
-
|
|
43
|
-
worker.should_receive :start
|
|
44
|
-
master.start_worker
|
|
45
|
-
end
|
|
29
|
+
let(:workers) { double :workers }
|
|
46
30
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
31
|
+
it 'stops all workers when receiving stop_all' do
|
|
32
|
+
allow(worker_pool).to receive(:workers) { workers }
|
|
33
|
+
allow(workers).to receive(:each).and_yield({ pid: 666 }).and_yield({ pid: 667 })
|
|
34
|
+
allow(workers).to receive(:length).and_return(2, 1, 0)
|
|
51
35
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
master.start_worker
|
|
55
|
-
end
|
|
36
|
+
expect(master).to receive(:stop_worker).with(666).ordered
|
|
37
|
+
expect(master).to receive(:stop_worker).with(667).ordered
|
|
56
38
|
|
|
57
|
-
|
|
58
|
-
let(:logger) { double(:logger) }
|
|
59
|
-
|
|
60
|
-
it 'should log the exception' do
|
|
61
|
-
master.stub(:logger).and_return logger
|
|
62
|
-
pipes.last.stub(:write)
|
|
63
|
-
worker.stub(:setup).and_raise :raised_by_spec
|
|
64
|
-
logger.should_receive :warn
|
|
65
|
-
master.start_worker
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
it 'should write to the writer pipe' do
|
|
69
|
-
master.stub(:logger).and_return logger
|
|
70
|
-
worker.stub(:setup).and_raise :raised_by_spec
|
|
71
|
-
logger.stub :warn
|
|
72
|
-
pipes.last.should_receive(:write).with Worker::UNCAUGHT_ERROR
|
|
73
|
-
master.start_worker
|
|
74
|
-
end
|
|
75
|
-
end
|
|
39
|
+
master.stop_all
|
|
76
40
|
end
|
|
77
41
|
|
|
78
|
-
describe '
|
|
42
|
+
describe 'and it receives stop_worker message' do
|
|
79
43
|
before :each do
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
pipes.last.stub(:close)
|
|
83
|
-
end
|
|
84
|
-
|
|
85
|
-
it 'increases worker_count' do
|
|
86
|
-
master.start_worker
|
|
87
|
-
master.worker_count.should eq(1)
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
it 'should open a pipe' do
|
|
91
|
-
IO.should_receive(:pipe) { pipes }
|
|
92
|
-
master.start_worker
|
|
44
|
+
allow(worker_pool).to receive(:workers) { workers }
|
|
45
|
+
allow(workers).to receive(:find) { |&block| block.call({ pid: 666 }) }
|
|
93
46
|
end
|
|
94
47
|
|
|
95
|
-
it 'should close the writer pipe' do
|
|
96
|
-
pipes.last.should_receive :close
|
|
97
|
-
master.start_worker
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
describe 'when it has running workers' do
|
|
103
|
-
before :each do
|
|
104
|
-
pipes.each { |p| p.stub :close }
|
|
105
|
-
IO.stub(:pipe) { pipes }
|
|
106
|
-
master.stub(:fork) { 666 }
|
|
107
|
-
master.start_worker
|
|
108
|
-
Process.stub(:kill).with('INT', 666)
|
|
109
|
-
Process.stub(:waitpid2).with(666)
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
describe 'and it receives stop_worker message' do
|
|
113
48
|
it 'kills a child with the INT signal' do
|
|
114
|
-
Process.
|
|
49
|
+
expect(Process).to receive(:kill).with('INT', 666)
|
|
115
50
|
master.stop_worker(666)
|
|
116
51
|
end
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
it 'stops all workers when receiving stop_all' do
|
|
120
|
-
Process.stub(:kill).with('INT', 666)
|
|
121
|
-
Process.stub(:wait2) { 666 }
|
|
122
52
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
end
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
describe 'when there are no running workers' do
|
|
130
|
-
describe 'and it receives stop_worker' do
|
|
131
|
-
it 'raises an error' do
|
|
132
|
-
expect { master.stop_worker(666) }.not_to raise_error
|
|
53
|
+
it 'kills nothing if no worker corresponds to the pid' do
|
|
54
|
+
expect(Process).not_to receive(:kill).with('INT', 667)
|
|
55
|
+
master.stop_worker(667)
|
|
133
56
|
end
|
|
134
57
|
end
|
|
135
58
|
|
|
136
|
-
describe 'and it receives stop_all' do
|
|
137
|
-
it 'does nothing' do
|
|
138
|
-
master.should_not_receive(:stop_worker)
|
|
139
|
-
master.stop_all
|
|
140
|
-
end
|
|
141
|
-
end
|
|
142
59
|
end
|
|
143
60
|
|
|
144
61
|
it 'starts the specified number of workers when started' do
|
|
145
|
-
master = Master.new nil, workers: 3
|
|
146
|
-
master.
|
|
147
|
-
master.
|
|
148
|
-
master.
|
|
62
|
+
master = Master.new nil, workers: 3, worker_pool: worker_pool
|
|
63
|
+
allow(master).to receive(:puts)
|
|
64
|
+
allow(master).to receive(:watch_for_output)
|
|
65
|
+
allow(master).to receive(:sleep)
|
|
66
|
+
expect(worker_pool).to receive(:spawn_worker).exactly(3).times
|
|
149
67
|
master.start
|
|
150
68
|
end
|
|
151
69
|
|
|
152
70
|
describe 'when number of workers is zero' do
|
|
153
|
-
let(:master) { Master.new nil, workers: 0 }
|
|
71
|
+
let(:master) { Master.new nil, workers: 0, worker_pool: worker_pool }
|
|
154
72
|
|
|
155
|
-
before(:each) { master.
|
|
73
|
+
before(:each) { allow(master).to receive(:puts) }
|
|
156
74
|
|
|
157
75
|
it 'should not start workers' do
|
|
158
|
-
master.
|
|
159
|
-
master.
|
|
76
|
+
allow(master).to receive(:trap_signals)
|
|
77
|
+
allow(master).to receive(:watch_for_output)
|
|
78
|
+
expect(worker_pool).not_to receive(:spawn_worker)
|
|
160
79
|
master.start
|
|
161
80
|
end
|
|
162
81
|
end
|
|
163
82
|
|
|
164
83
|
it 'attaches a signal handler when started' do
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
84
|
+
allow(worker_pool).to receive(:spawn_worker)
|
|
85
|
+
allow(master).to receive(:watch_for_output)
|
|
86
|
+
|
|
87
|
+
expect(Signal).to receive(:trap).with(:TTIN)
|
|
88
|
+
expect(Signal).to receive(:trap).with(:INT)
|
|
89
|
+
expect(Signal).to receive(:trap).with(:TTOU)
|
|
90
|
+
|
|
170
91
|
master.start
|
|
171
92
|
end
|
|
172
93
|
|
|
173
94
|
it 'should watch for output' do
|
|
174
|
-
|
|
175
|
-
master.
|
|
95
|
+
allow(worker_pool).to receive(:spawn_worker)
|
|
96
|
+
allow(master).to receive(:trap_signals)
|
|
97
|
+
expect(master).to receive(:watch_for_output)
|
|
176
98
|
master.start
|
|
177
99
|
end
|
|
178
100
|
|
|
179
101
|
it 'can resolve a wpid from a reader pipe' do
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
master.
|
|
184
|
-
master.start_worker
|
|
185
|
-
|
|
186
|
-
master.send(:worker_pid, pipes.first).should eq(666)
|
|
102
|
+
pipe = double :pipe
|
|
103
|
+
allow(pipe).to receive(:fileno) { 123 }
|
|
104
|
+
allow(worker_pool).to receive(:workers) { [{ pid: 666, reader: pipe }] }
|
|
105
|
+
expect(master.send(:worker_pid, pipe)).to eq(666)
|
|
187
106
|
end
|
|
188
107
|
|
|
189
108
|
it 'raises if it can\'t resolve a wpid from a reader pipe' do
|
|
109
|
+
allow(worker_pool).to receive(:workers) { [] }
|
|
190
110
|
expect { master.send(:worker_pid, pipes.first) }.to raise_error("Unknown worker pipe")
|
|
191
111
|
end
|
|
192
112
|
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require_relative '../../lib/sisyphus/simple_execution_strategy'
|
|
3
|
+
|
|
4
|
+
module Sisyphus
|
|
5
|
+
describe SimpleExecutionStrategy do
|
|
6
|
+
|
|
7
|
+
let(:job) { double :job }
|
|
8
|
+
let(:strategy) { SimpleExecutionStrategy.new }
|
|
9
|
+
|
|
10
|
+
it 'should perform the job when executed' do
|
|
11
|
+
expect(job).to receive(:perform)
|
|
12
|
+
strategy.execute job
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it 'should call the error_handler if the job fails' do
|
|
16
|
+
error_message = "This is a horrible failure.. The Universe is probably ending!"
|
|
17
|
+
error = Exception.new(error_message)
|
|
18
|
+
process_name = "uber awesome process name"
|
|
19
|
+
allow(job).to receive(:perform) { fail error }
|
|
20
|
+
allow(strategy).to receive(:process_name) { process_name }
|
|
21
|
+
strategy.execute job, ->(name, raised_error) {
|
|
22
|
+
expect(name).to eq(process_name)
|
|
23
|
+
expect(raised_error).to eq(error)
|
|
24
|
+
}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require_relative '../../lib/sisyphus/master'
|
|
3
|
+
require_relative '../../lib/sisyphus/worker_pool'
|
|
4
|
+
|
|
5
|
+
module Sisyphus
|
|
6
|
+
describe WorkerPool do
|
|
7
|
+
|
|
8
|
+
subject(:worker_pool) { WorkerPool.new worker_factory }
|
|
9
|
+
|
|
10
|
+
describe 'when receiving the spawn_worker message' do
|
|
11
|
+
|
|
12
|
+
let(:job) { double :job }
|
|
13
|
+
let(:worker_factory) { Master.new(job) }
|
|
14
|
+
let(:pipes) { [double(:output), double(:input)] }
|
|
15
|
+
|
|
16
|
+
it 'retrieves a worker from the worker_factory' do
|
|
17
|
+
allow(worker_pool).to receive(:fork) { 3267 }
|
|
18
|
+
expect(worker_factory).to receive(:create_worker).and_call_original
|
|
19
|
+
worker_pool.spawn_worker
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it 'forks' do
|
|
23
|
+
expect(worker_pool).to receive(:fork) { 666 }
|
|
24
|
+
worker_pool.spawn_worker
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe 'in the worker process' do
|
|
28
|
+
|
|
29
|
+
let(:worker) { double :worker }
|
|
30
|
+
|
|
31
|
+
before :each do
|
|
32
|
+
allow(worker_pool).to receive(:fork) { nil }
|
|
33
|
+
allow(worker_pool).to receive(:process_name=)
|
|
34
|
+
allow(worker).to receive(:start)
|
|
35
|
+
allow(worker).to receive(:atfork_child)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it 'runs Worker#atfork_child' do
|
|
39
|
+
allow(worker_factory).to receive(:create_worker) { worker }
|
|
40
|
+
expect(worker).to receive(:atfork_child).with(no_args)
|
|
41
|
+
worker_pool.spawn_worker
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it 'renames the process' do
|
|
45
|
+
allow(worker_factory).to receive(:create_worker) { worker }
|
|
46
|
+
expect(worker_pool).to receive(:process_name=).with("Worker #{Process.pid}")
|
|
47
|
+
worker_pool.spawn_worker
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it 'starts the worker' do
|
|
51
|
+
allow(worker_factory).to receive(:create_worker) { worker }
|
|
52
|
+
allow(worker).to receive(:atfork_child)
|
|
53
|
+
expect(worker).to receive(:start)
|
|
54
|
+
worker_pool.spawn_worker
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
describe 'in the master process' do
|
|
60
|
+
|
|
61
|
+
before :each do
|
|
62
|
+
allow(worker_pool).to receive(:fork) { Process.pid }
|
|
63
|
+
allow(pipes.last).to receive(:close)
|
|
64
|
+
allow(IO).to receive(:pipe) { pipes }
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it 'closes the input pipe' do
|
|
68
|
+
worker = double :worker
|
|
69
|
+
allow(worker).to receive(:to_master)
|
|
70
|
+
allow(worker_factory).to receive(:create_worker) { worker }
|
|
71
|
+
expect(worker).to receive(:atfork_parent).with(no_args)
|
|
72
|
+
worker_pool.spawn_worker
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
it 'adds the worker pid and output pipe to the list of workers' do
|
|
76
|
+
expect(worker_pool.workers).to receive(:<<).with({ pid: Process.pid, reader: pipes.first })
|
|
77
|
+
worker_pool.spawn_worker
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -1,126 +1,128 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
1
2
|
require_relative '../../lib/sisyphus/worker'
|
|
2
3
|
|
|
3
4
|
module Sisyphus
|
|
4
5
|
describe Worker do
|
|
5
6
|
let(:job) { double :job }
|
|
6
|
-
let(:
|
|
7
|
+
let(:execution_strategy) { double :execution_strategy }
|
|
7
8
|
let(:logger) { double :logger }
|
|
8
|
-
let(:worker) { Worker.new job, output, logger }
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
worker.
|
|
10
|
+
subject(:worker) { Worker.new job, execution_strategy, logger }
|
|
11
|
+
|
|
12
|
+
it 'sets up itself and executes run when started' do
|
|
13
|
+
expect(worker).to receive(:setup).ordered
|
|
14
|
+
expect(worker).to receive(:run).ordered
|
|
14
15
|
worker.start
|
|
15
16
|
end
|
|
16
17
|
|
|
17
|
-
it '
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
it 'traps INT signals before setting up the job' do
|
|
19
|
+
allow(job).to receive(:respond_to?).with(:setup) { true }
|
|
20
|
+
expect(Signal).to receive(:trap).with('INT').ordered
|
|
21
|
+
expect(job).to receive(:setup).ordered
|
|
22
|
+
worker.setup
|
|
21
23
|
end
|
|
22
24
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
end
|
|
25
|
+
it 'does not perform the job when it has been stopped' do
|
|
26
|
+
worker.stop
|
|
27
|
+
allow(worker).to receive(:exit!)
|
|
28
|
+
expect(worker).not_to receive(:perform_job)
|
|
29
|
+
worker.run
|
|
29
30
|
end
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
worker.setup
|
|
36
|
-
end
|
|
32
|
+
it 'will not run if it has not been set up' do
|
|
33
|
+
expect(worker).not_to receive(:perform_job)
|
|
34
|
+
allow(worker).to receive(:exit!)
|
|
35
|
+
worker.run
|
|
37
36
|
end
|
|
38
37
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
38
|
+
it 'uses execution_strategy to perform the job' do
|
|
39
|
+
expect(execution_strategy).to receive(:execute).with job, an_instance_of(Proc)
|
|
40
|
+
worker.perform_job
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it 'passes the error_handler to the execution strategy' do
|
|
44
|
+
allow(execution_strategy).to receive(:execute).with job, an_instance_of(Proc)
|
|
45
|
+
expect(worker).to receive(:error_handler) { ->{} }
|
|
46
|
+
worker.perform_job
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it 'only closes the output in atfork_parent' do
|
|
50
|
+
expect(worker.output).to receive(:close)
|
|
51
|
+
expect(worker.to_master).not_to receive(:close)
|
|
52
|
+
worker.atfork_parent
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it 'only closes the to_master in atfork_child' do
|
|
56
|
+
expect(worker.to_master).to receive(:close)
|
|
57
|
+
expect(worker.output).not_to receive(:close)
|
|
58
|
+
worker.atfork_child
|
|
59
|
+
end
|
|
43
60
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
61
|
+
context 'the error_handler' do
|
|
62
|
+
|
|
63
|
+
it 'writes the UNCAUGHT_ERROR to output' do
|
|
64
|
+
allow(logger).to receive(:warn)
|
|
65
|
+
expect(worker.output).to receive(:write).with Worker::UNCAUGHT_ERROR
|
|
66
|
+
worker.error_handler.call(:name, :error)
|
|
48
67
|
end
|
|
49
68
|
|
|
50
|
-
it '
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
worker.
|
|
69
|
+
it 'logs the error being thrown' do
|
|
70
|
+
the_name = :the_name
|
|
71
|
+
the_exception = :the_exception
|
|
72
|
+
expect(worker.logger).to receive(:warn) do |name, &block|
|
|
73
|
+
expect(name).to eq(the_name)
|
|
74
|
+
expect(block.call).to eq(the_exception)
|
|
75
|
+
end
|
|
76
|
+
worker.error_handler.call(the_name, the_exception)
|
|
54
77
|
end
|
|
55
78
|
|
|
56
|
-
it '
|
|
57
|
-
|
|
58
|
-
worker.
|
|
59
|
-
|
|
60
|
-
worker.
|
|
61
|
-
worker.
|
|
79
|
+
it 'does not write UNCAUGHT_ERROR to output if the worker is stopped' do
|
|
80
|
+
allow(worker).to receive(:stopped?) { true }
|
|
81
|
+
expect(worker.output).to_not receive(:write)
|
|
82
|
+
worker.error_handler.call(:name, :error)
|
|
83
|
+
expect(worker.output).to_not receive(:write)
|
|
84
|
+
worker.error_handler.call(:name, :error)
|
|
62
85
|
end
|
|
63
86
|
|
|
64
|
-
|
|
65
|
-
it 'should exit with a non-zero status' do
|
|
66
|
-
logger.stub :warn
|
|
67
|
-
job.stub(:perform).and_raise Exception.new "should be rescued!"
|
|
68
|
-
worker.should_receive(:exit!).with(1)
|
|
69
|
-
worker.send :perform_job
|
|
70
|
-
end
|
|
87
|
+
end
|
|
71
88
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
end
|
|
89
|
+
context 'when job does not respond to :setup' do
|
|
90
|
+
it 'does not call job.setup' do
|
|
91
|
+
allow(job).to receive(:respond_to?).with(:setup) { false }
|
|
92
|
+
expect(job).not_to receive(:setup)
|
|
93
|
+
worker.setup
|
|
78
94
|
end
|
|
79
95
|
end
|
|
80
96
|
|
|
81
|
-
context '
|
|
82
|
-
let(:status) { double(:status) }
|
|
97
|
+
context 'when job responds to :setup' do
|
|
83
98
|
|
|
84
99
|
before :each do
|
|
85
|
-
|
|
100
|
+
allow(job).to receive(:respond_to?).with(:setup) { true }
|
|
86
101
|
end
|
|
87
102
|
|
|
88
|
-
it '
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
Process.should_receive(:waitpid2).with(666) { [666, status] }
|
|
92
|
-
worker.send :perform_job
|
|
103
|
+
it 'sets up the job' do
|
|
104
|
+
expect(job).to receive(:setup)
|
|
105
|
+
worker.setup
|
|
93
106
|
end
|
|
94
107
|
|
|
95
|
-
context '
|
|
108
|
+
context 'and job#setup raises an exception' do
|
|
109
|
+
|
|
96
110
|
before :each do
|
|
97
|
-
|
|
98
|
-
|
|
111
|
+
allow(job).to receive(:setup).and_raise(Exception)
|
|
112
|
+
allow(logger).to receive(:warn)
|
|
99
113
|
end
|
|
100
114
|
|
|
101
|
-
it '
|
|
102
|
-
|
|
103
|
-
worker.send :perform_job
|
|
115
|
+
it 'handles the exception' do
|
|
116
|
+
expect { worker.setup }.not_to raise_error(Exception)
|
|
104
117
|
end
|
|
105
118
|
|
|
106
|
-
it
|
|
107
|
-
worker.
|
|
108
|
-
|
|
109
|
-
worker.send :perform_job
|
|
119
|
+
it 'calls the error_handler in the rescue block' do
|
|
120
|
+
expect(worker.output).to receive(:write).with(Worker::UNCAUGHT_ERROR)
|
|
121
|
+
worker.setup
|
|
110
122
|
end
|
|
111
|
-
end
|
|
112
123
|
|
|
113
|
-
context 'when exit status from child is zero' do
|
|
114
|
-
before :each do
|
|
115
|
-
status.stub(:success?) { true }
|
|
116
|
-
Process.stub(:waitpid2) { [666, status] }
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
it "doesn't write error byte to output" do
|
|
120
|
-
output.should_not_receive :write
|
|
121
|
-
worker.send :perform_job
|
|
122
|
-
end
|
|
123
124
|
end
|
|
124
125
|
end
|
|
126
|
+
|
|
125
127
|
end
|
|
126
128
|
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
|
3
|
+
# Require this file using `require "spec_helper"` to ensure that it is only
|
|
4
|
+
# loaded once.
|
|
5
|
+
#
|
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
|
7
|
+
RSpec.configure do |config|
|
|
8
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
|
9
|
+
config.run_all_when_everything_filtered = true
|
|
10
|
+
config.filter_run :focus
|
|
11
|
+
|
|
12
|
+
# Run specs in random order to surface order dependencies. If you find an
|
|
13
|
+
# order dependency and want to debug it, you can fix the order by providing
|
|
14
|
+
# the seed, which is printed after each run.
|
|
15
|
+
# --seed 1234
|
|
16
|
+
config.order = 'random'
|
|
17
|
+
end
|