concurrent-ruby 0.6.1 → 0.7.0.rc0
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/README.md +1 -1
- data/lib/concurrent.rb +3 -4
- data/lib/concurrent/atomic.rb +46 -0
- data/lib/concurrent/atomic_reference/concurrent_update_error.rb +7 -0
- data/lib/concurrent/atomic_reference/delegated_update.rb +28 -0
- data/lib/concurrent/atomic_reference/direct_update.rb +28 -0
- data/lib/concurrent/atomic_reference/jruby.rb +8 -0
- data/lib/concurrent/atomic_reference/mutex_atomic.rb +47 -0
- data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +24 -0
- data/lib/concurrent/atomic_reference/rbx.rb +16 -0
- data/lib/concurrent/atomic_reference/ruby.rb +16 -0
- data/lib/concurrent/atomics.rb +1 -1
- data/lib/concurrent/configuration.rb +1 -1
- data/lib/concurrent/supervisor.rb +1 -1
- data/lib/concurrent/timer_task.rb +0 -36
- data/lib/concurrent/version.rb +1 -1
- data/lib/concurrent_ruby_ext.so +0 -0
- data/lib/extension_helper.rb +9 -0
- metadata +16 -148
- data/lib/concurrent/actor/actor.rb +0 -270
- data/lib/concurrent/actor/postable.rb +0 -102
- data/lib/concurrent/actors.rb +0 -2
- data/lib/concurrent/atomic/atomic.rb +0 -48
- data/lib/concurrent/runnable.rb +0 -90
- data/lib/concurrent/stoppable.rb +0 -20
- data/spec/concurrent/actor/actor_spec.rb +0 -376
- data/spec/concurrent/actor/postable_shared.rb +0 -218
- data/spec/concurrent/actress_spec.rb +0 -211
- data/spec/concurrent/agent_spec.rb +0 -500
- data/spec/concurrent/async_spec.rb +0 -352
- data/spec/concurrent/atomic/atomic_boolean_spec.rb +0 -172
- data/spec/concurrent/atomic/atomic_fixnum_spec.rb +0 -186
- data/spec/concurrent/atomic/atomic_spec.rb +0 -133
- data/spec/concurrent/atomic/condition_spec.rb +0 -171
- data/spec/concurrent/atomic/copy_on_notify_observer_set_spec.rb +0 -10
- data/spec/concurrent/atomic/copy_on_write_observer_set_spec.rb +0 -10
- data/spec/concurrent/atomic/count_down_latch_spec.rb +0 -151
- data/spec/concurrent/atomic/cyclic_barrier_spec.rb +0 -248
- data/spec/concurrent/atomic/event_spec.rb +0 -200
- data/spec/concurrent/atomic/observer_set_shared.rb +0 -242
- data/spec/concurrent/atomic/thread_local_var_spec.rb +0 -113
- data/spec/concurrent/channel/buffered_channel_spec.rb +0 -151
- data/spec/concurrent/channel/channel_spec.rb +0 -39
- data/spec/concurrent/channel/probe_spec.rb +0 -77
- data/spec/concurrent/channel/unbuffered_channel_spec.rb +0 -132
- data/spec/concurrent/collection/blocking_ring_buffer_spec.rb +0 -149
- data/spec/concurrent/collection/priority_queue_spec.rb +0 -317
- data/spec/concurrent/collection/ring_buffer_spec.rb +0 -126
- data/spec/concurrent/configuration_spec.rb +0 -69
- data/spec/concurrent/dataflow_spec.rb +0 -242
- data/spec/concurrent/delay_spec.rb +0 -91
- data/spec/concurrent/dereferenceable_shared.rb +0 -146
- data/spec/concurrent/exchanger_spec.rb +0 -66
- data/spec/concurrent/executor/cached_thread_pool_shared.rb +0 -115
- data/spec/concurrent/executor/fixed_thread_pool_shared.rb +0 -136
- data/spec/concurrent/executor/global_thread_pool_shared.rb +0 -35
- data/spec/concurrent/executor/immediate_executor_spec.rb +0 -12
- data/spec/concurrent/executor/java_cached_thread_pool_spec.rb +0 -44
- data/spec/concurrent/executor/java_fixed_thread_pool_spec.rb +0 -64
- data/spec/concurrent/executor/java_single_thread_executor_spec.rb +0 -21
- data/spec/concurrent/executor/java_thread_pool_executor_spec.rb +0 -71
- data/spec/concurrent/executor/per_thread_executor_spec.rb +0 -57
- data/spec/concurrent/executor/ruby_cached_thread_pool_spec.rb +0 -69
- data/spec/concurrent/executor/ruby_fixed_thread_pool_spec.rb +0 -39
- data/spec/concurrent/executor/ruby_single_thread_executor_spec.rb +0 -18
- data/spec/concurrent/executor/ruby_thread_pool_executor_spec.rb +0 -171
- data/spec/concurrent/executor/safe_task_executor_spec.rb +0 -103
- data/spec/concurrent/executor/thread_pool_class_cast_spec.rb +0 -52
- data/spec/concurrent/executor/thread_pool_executor_shared.rb +0 -155
- data/spec/concurrent/executor/thread_pool_shared.rb +0 -269
- data/spec/concurrent/executor/timer_set_spec.rb +0 -183
- data/spec/concurrent/future_spec.rb +0 -329
- data/spec/concurrent/ivar_spec.rb +0 -215
- data/spec/concurrent/mvar_spec.rb +0 -380
- data/spec/concurrent/obligation_shared.rb +0 -102
- data/spec/concurrent/obligation_spec.rb +0 -282
- data/spec/concurrent/observable_shared.rb +0 -177
- data/spec/concurrent/observable_spec.rb +0 -56
- data/spec/concurrent/options_parser_spec.rb +0 -71
- data/spec/concurrent/promise_spec.rb +0 -367
- data/spec/concurrent/runnable_shared.rb +0 -68
- data/spec/concurrent/runnable_spec.rb +0 -235
- data/spec/concurrent/scheduled_task_spec.rb +0 -340
- data/spec/concurrent/stoppable_shared.rb +0 -37
- data/spec/concurrent/supervisor_spec.rb +0 -1149
- data/spec/concurrent/timer_task_spec.rb +0 -256
- data/spec/concurrent/tvar_spec.rb +0 -137
- data/spec/concurrent/utility/processor_count_spec.rb +0 -20
- data/spec/concurrent/utility/timeout_spec.rb +0 -50
- data/spec/concurrent/utility/timer_spec.rb +0 -52
- data/spec/spec_helper.rb +0 -41
- data/spec/support/example_group_extensions.rb +0 -52
- data/spec/support/less_than_or_equal_to_matcher.rb +0 -5
@@ -1,37 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
share_examples_for :stoppable do
|
4
|
-
|
5
|
-
after(:each) do
|
6
|
-
subject.stop
|
7
|
-
end
|
8
|
-
|
9
|
-
context 'stopping' do
|
10
|
-
|
11
|
-
it 'raises an exception when #before_stop does not receive a block' do
|
12
|
-
expect {
|
13
|
-
subject.before_stop
|
14
|
-
}.to raise_error(ArgumentError)
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'raises an exception if #before_stop is called more than once' do
|
18
|
-
subject.before_stop{ nil }
|
19
|
-
expect {
|
20
|
-
subject.before_stop{ nil }
|
21
|
-
}.to raise_error(Concurrent::Runnable::LifecycleError)
|
22
|
-
end
|
23
|
-
|
24
|
-
it 'returns self from #before_stop' do
|
25
|
-
task = subject
|
26
|
-
task.before_stop{ nil }.should eq task
|
27
|
-
end
|
28
|
-
|
29
|
-
it 'calls the #before_stop block when stopping' do
|
30
|
-
@expected = false
|
31
|
-
subject.before_stop{ @expected = true }
|
32
|
-
subject.stop
|
33
|
-
sleep(0.1)
|
34
|
-
@expected.should be_true
|
35
|
-
end
|
36
|
-
end
|
37
|
-
end
|
@@ -1,1149 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'timecop'
|
3
|
-
require_relative 'runnable_shared'
|
4
|
-
|
5
|
-
module Concurrent
|
6
|
-
|
7
|
-
describe Supervisor do
|
8
|
-
|
9
|
-
let(:worker_class) do
|
10
|
-
Class.new {
|
11
|
-
attr_reader :start_count, :stop_count
|
12
|
-
def run() @start_count ||= 0; @start_count += 1; return true; end
|
13
|
-
def stop() @stop_count ||= 0; @stop_count += 1; return true; end
|
14
|
-
def running?() return true; end
|
15
|
-
}
|
16
|
-
end
|
17
|
-
|
18
|
-
let(:sleeper_class) do
|
19
|
-
Class.new(worker_class) {
|
20
|
-
def run() super(); sleep; end
|
21
|
-
}
|
22
|
-
end
|
23
|
-
|
24
|
-
let(:stopper_class) do
|
25
|
-
Class.new(worker_class) {
|
26
|
-
attr_reader :latch
|
27
|
-
def initialize(sleep_time = 0.2)
|
28
|
-
@sleep_time = sleep_time
|
29
|
-
@latch = Concurrent::CountDownLatch.new(1)
|
30
|
-
end
|
31
|
-
def run
|
32
|
-
super
|
33
|
-
sleep(@sleep_time)
|
34
|
-
@latch.count_down
|
35
|
-
end
|
36
|
-
}
|
37
|
-
end
|
38
|
-
|
39
|
-
let(:error_class) do
|
40
|
-
Class.new(worker_class) {
|
41
|
-
def run() super(); raise StandardError; end
|
42
|
-
}
|
43
|
-
end
|
44
|
-
|
45
|
-
let(:runner_class) do
|
46
|
-
Class.new(worker_class) {
|
47
|
-
attr_accessor :stopped
|
48
|
-
def run()
|
49
|
-
super()
|
50
|
-
stopped = false
|
51
|
-
loop do
|
52
|
-
break if stopped
|
53
|
-
Thread.pass
|
54
|
-
end
|
55
|
-
end
|
56
|
-
def stop() super(); stopped = true; end
|
57
|
-
}
|
58
|
-
end
|
59
|
-
|
60
|
-
let(:worker){ worker_class.new }
|
61
|
-
|
62
|
-
subject{ Supervisor.new(strategy: :one_for_one, monitor_interval: 0.1) }
|
63
|
-
|
64
|
-
it_should_behave_like :runnable
|
65
|
-
|
66
|
-
after(:each) do
|
67
|
-
subject.stop
|
68
|
-
kill_rogue_threads
|
69
|
-
sleep(0.1)
|
70
|
-
end
|
71
|
-
|
72
|
-
context '#initialize' do
|
73
|
-
|
74
|
-
it 'sets the initial length to zero' do
|
75
|
-
supervisor = Supervisor.new
|
76
|
-
supervisor.length.should == 0
|
77
|
-
end
|
78
|
-
|
79
|
-
it 'sets the initial length to one when a worker is provided' do
|
80
|
-
supervisor = Supervisor.new(worker: worker)
|
81
|
-
supervisor.length.should == 1
|
82
|
-
end
|
83
|
-
|
84
|
-
it 'sets the initial state to stopped' do
|
85
|
-
supervisor = Supervisor.new
|
86
|
-
supervisor.should_not be_running
|
87
|
-
end
|
88
|
-
|
89
|
-
it 'uses the given monitor interval' do
|
90
|
-
supervisor = Supervisor.new
|
91
|
-
supervisor.monitor_interval.should == Supervisor::DEFAULT_MONITOR_INTERVAL
|
92
|
-
end
|
93
|
-
|
94
|
-
it 'uses the default monitor interval when none given' do
|
95
|
-
supervisor = Supervisor.new(monitor_interval: 5)
|
96
|
-
supervisor.monitor_interval.should == 5
|
97
|
-
end
|
98
|
-
|
99
|
-
it 'raises an exception when given an invalid monitor interval' do
|
100
|
-
lambda {
|
101
|
-
Supervisor.new(monitor_interval: -1)
|
102
|
-
}.should raise_error(ArgumentError)
|
103
|
-
|
104
|
-
lambda {
|
105
|
-
Supervisor.new(monitor_interval: 'bogus')
|
106
|
-
}.should raise_error(ArgumentError)
|
107
|
-
end
|
108
|
-
|
109
|
-
it 'uses the given restart strategy' do
|
110
|
-
supervisor = Supervisor.new(restart_strategy: :rest_for_one)
|
111
|
-
supervisor.restart_strategy.should eq :rest_for_one
|
112
|
-
end
|
113
|
-
|
114
|
-
it 'uses :one_for_one when no restart strategy given' do
|
115
|
-
supervisor = Supervisor.new
|
116
|
-
supervisor.restart_strategy.should eq :one_for_one
|
117
|
-
end
|
118
|
-
|
119
|
-
it 'raises an exception when given an invalid restart strategy' do
|
120
|
-
Supervisor::RESTART_STRATEGIES.each do |strategy|
|
121
|
-
lambda {
|
122
|
-
supervisor = Supervisor.new(strategy: strategy)
|
123
|
-
}.should_not raise_error
|
124
|
-
end
|
125
|
-
|
126
|
-
lambda {
|
127
|
-
supervisor = Supervisor.new(strategy: :bogus)
|
128
|
-
}.should raise_error(ArgumentError)
|
129
|
-
end
|
130
|
-
|
131
|
-
it 'uses the given maximum restart value' do
|
132
|
-
supervisor = Supervisor.new(max_restart: 3)
|
133
|
-
supervisor.max_r.should == 3
|
134
|
-
|
135
|
-
supervisor = Supervisor.new(max_r: 3)
|
136
|
-
supervisor.max_restart.should == 3
|
137
|
-
end
|
138
|
-
|
139
|
-
it 'uses the default maximum restart value when none given' do
|
140
|
-
supervisor = Supervisor.new
|
141
|
-
supervisor.max_restart.should == Supervisor::DEFAULT_MAX_RESTART
|
142
|
-
supervisor.max_r.should == Supervisor::DEFAULT_MAX_RESTART
|
143
|
-
end
|
144
|
-
|
145
|
-
it 'raises an exception when given an invalid maximum restart value' do
|
146
|
-
lambda {
|
147
|
-
Supervisor.new(max_restart: -1)
|
148
|
-
}.should raise_error(ArgumentError)
|
149
|
-
|
150
|
-
lambda {
|
151
|
-
Supervisor.new(max_restart: 'bogus')
|
152
|
-
}.should raise_error(ArgumentError)
|
153
|
-
end
|
154
|
-
|
155
|
-
it 'uses the given maximum time value' do
|
156
|
-
supervisor = Supervisor.new(max_time: 3)
|
157
|
-
supervisor.max_t.should == 3
|
158
|
-
|
159
|
-
supervisor = Supervisor.new(max_t: 3)
|
160
|
-
supervisor.max_time.should == 3
|
161
|
-
end
|
162
|
-
|
163
|
-
it 'uses the default maximum time value when none given' do
|
164
|
-
supervisor = Supervisor.new
|
165
|
-
supervisor.max_time.should == Supervisor::DEFAULT_MAX_TIME
|
166
|
-
supervisor.max_t.should == Supervisor::DEFAULT_MAX_TIME
|
167
|
-
end
|
168
|
-
|
169
|
-
it 'raises an exception when given an invalid maximum time value' do
|
170
|
-
lambda {
|
171
|
-
Supervisor.new(max_time: -1)
|
172
|
-
}.should raise_error(ArgumentError)
|
173
|
-
|
174
|
-
lambda {
|
175
|
-
Supervisor.new(max_time: 'bogus')
|
176
|
-
}.should raise_error(ArgumentError)
|
177
|
-
end
|
178
|
-
end
|
179
|
-
|
180
|
-
context '#run' do
|
181
|
-
|
182
|
-
it 'runs the monitor' do
|
183
|
-
subject.should_receive(:monitor).with(no_args()).at_least(1).times
|
184
|
-
t = Thread.new{ subject.run }
|
185
|
-
sleep(0.1)
|
186
|
-
subject.stop
|
187
|
-
Thread.kill(t) unless t.nil?
|
188
|
-
end
|
189
|
-
|
190
|
-
it 'calls #run on all workers' do
|
191
|
-
supervisor = Supervisor.new(worker: worker)
|
192
|
-
# must stub AFTER adding or else #add_worker will reject
|
193
|
-
worker.should_receive(:run).with(no_args())
|
194
|
-
t = Thread.new{ supervisor.run }
|
195
|
-
sleep(0.1)
|
196
|
-
supervisor.stop
|
197
|
-
Thread.kill(t)
|
198
|
-
end
|
199
|
-
|
200
|
-
it 'sets the state to running' do
|
201
|
-
t = Thread.new{ subject.run }
|
202
|
-
sleep(0.1)
|
203
|
-
subject.should be_running
|
204
|
-
subject.stop
|
205
|
-
Thread.kill(t)
|
206
|
-
end
|
207
|
-
|
208
|
-
it 'raises an exception when already running' do
|
209
|
-
@thread = nil
|
210
|
-
subject.run!
|
211
|
-
lambda {
|
212
|
-
@thread = Thread.new do
|
213
|
-
Thread.current.abort_on_exception = true
|
214
|
-
subject.run
|
215
|
-
end
|
216
|
-
sleep(0.1)
|
217
|
-
}.should raise_error(StandardError)
|
218
|
-
subject.stop
|
219
|
-
Thread.kill(@thread) unless @thread.nil?
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
223
|
-
context '#run!' do
|
224
|
-
|
225
|
-
it 'runs the monitor thread' do
|
226
|
-
thread = Thread.new{ nil }
|
227
|
-
Thread.should_receive(:new).with(no_args()).and_return(thread)
|
228
|
-
subject.run!
|
229
|
-
sleep(0.1)
|
230
|
-
end
|
231
|
-
|
232
|
-
it 'calls #run on all workers' do
|
233
|
-
supervisor = Supervisor.new(worker: worker)
|
234
|
-
# must stub AFTER adding or else #add_worker will reject
|
235
|
-
worker.should_receive(:run).with(no_args())
|
236
|
-
supervisor.run!
|
237
|
-
sleep(0.1)
|
238
|
-
end
|
239
|
-
|
240
|
-
it 'sets the state to running' do
|
241
|
-
subject.run!
|
242
|
-
subject.should be_running
|
243
|
-
end
|
244
|
-
|
245
|
-
it 'raises an exception when already running' do
|
246
|
-
subject.run!
|
247
|
-
lambda {
|
248
|
-
subject.run!
|
249
|
-
}.should raise_error(StandardError)
|
250
|
-
end
|
251
|
-
end
|
252
|
-
|
253
|
-
context '#stop' do
|
254
|
-
|
255
|
-
def mock_thread(status = 'run')
|
256
|
-
thread = double('thread')
|
257
|
-
thread.should_receive(:status).with(no_args()).and_return(status)
|
258
|
-
thread.stub(:join).with(any_args()).and_return(thread)
|
259
|
-
Thread.stub(:new).with(no_args()).and_return(thread)
|
260
|
-
return thread
|
261
|
-
end
|
262
|
-
|
263
|
-
it 'wakes the monitor thread if sleeping' do
|
264
|
-
thread = mock_thread('sleep')
|
265
|
-
thread.should_receive(:run).once.with(no_args())
|
266
|
-
|
267
|
-
subject.run!
|
268
|
-
sleep(0.1)
|
269
|
-
subject.stop
|
270
|
-
end
|
271
|
-
|
272
|
-
it 'kills the monitor thread if it does not wake up' do
|
273
|
-
thread = mock_thread('run')
|
274
|
-
thread.should_receive(:join).with(any_args()).and_return(nil)
|
275
|
-
thread.should_receive(:kill).with(no_args())
|
276
|
-
|
277
|
-
subject.run!
|
278
|
-
sleep(0.1)
|
279
|
-
subject.stop
|
280
|
-
end
|
281
|
-
|
282
|
-
it 'calls #stop on all workers' do
|
283
|
-
workers = (1..3).collect{ runner_class.new }
|
284
|
-
workers.each{|worker| subject.add_worker(worker)}
|
285
|
-
# must stub AFTER adding or else #add_worker will reject
|
286
|
-
workers.each{|worker| worker.should_receive(:stop).with(no_args())}
|
287
|
-
subject.run!
|
288
|
-
sleep(0.1)
|
289
|
-
subject.stop
|
290
|
-
end
|
291
|
-
|
292
|
-
it 'sets the state to stopped' do
|
293
|
-
subject.run!
|
294
|
-
subject.stop
|
295
|
-
subject.should_not be_running
|
296
|
-
end
|
297
|
-
|
298
|
-
it 'returns true immediately when already stopped' do
|
299
|
-
subject.stop.should be_true
|
300
|
-
end
|
301
|
-
|
302
|
-
it 'unblocks a thread blocked by #run and exits normally' do
|
303
|
-
supervisor = Supervisor.new(monitor_interval: 0.1)
|
304
|
-
@thread = Thread.new{ sleep(0.5); supervisor.stop }
|
305
|
-
sleep(0.1)
|
306
|
-
lambda {
|
307
|
-
Concurrent::timeout(1){ supervisor.run }
|
308
|
-
}.should_not raise_error
|
309
|
-
Thread.kill(@thread) unless @thread.nil?
|
310
|
-
end
|
311
|
-
end
|
312
|
-
|
313
|
-
context '#running?' do
|
314
|
-
|
315
|
-
it 'returns true when running' do
|
316
|
-
subject.run!
|
317
|
-
subject.should be_running
|
318
|
-
end
|
319
|
-
|
320
|
-
it 'returns false when stopped' do
|
321
|
-
subject.run!
|
322
|
-
subject.stop
|
323
|
-
subject.should_not be_running
|
324
|
-
end
|
325
|
-
end
|
326
|
-
|
327
|
-
context '#length' do
|
328
|
-
|
329
|
-
it 'returns a count of attached workers' do
|
330
|
-
workers = (1..3).collect{ worker.dup }
|
331
|
-
workers.each{|worker| subject.add_worker(worker)}
|
332
|
-
subject.length.should == 3
|
333
|
-
end
|
334
|
-
end
|
335
|
-
|
336
|
-
context '#count' do
|
337
|
-
|
338
|
-
let(:stoppers){ Array.new }
|
339
|
-
|
340
|
-
let(:busy_supervisor) do
|
341
|
-
supervisor = Supervisor.new(monitor_interval: 60)
|
342
|
-
3.times do
|
343
|
-
supervisor.add_worker(sleeper_class.new)
|
344
|
-
supervisor.add_worker(error_class.new)
|
345
|
-
supervisor.add_worker(runner_class.new)
|
346
|
-
|
347
|
-
stopper = stopper_class.new
|
348
|
-
stoppers << stopper
|
349
|
-
supervisor.add_worker(stopper)
|
350
|
-
end
|
351
|
-
supervisor
|
352
|
-
end
|
353
|
-
|
354
|
-
let!(:total_count){ 12 }
|
355
|
-
let!(:active_count){ 6 }
|
356
|
-
let!(:sleeping_count){ 3 }
|
357
|
-
let!(:running_count){ 3 }
|
358
|
-
let!(:aborting_count){ 3 }
|
359
|
-
let!(:stopped_count){ 3 }
|
360
|
-
let!(:abend_count){ 3 }
|
361
|
-
|
362
|
-
after(:each) do
|
363
|
-
busy_supervisor.stop
|
364
|
-
end
|
365
|
-
|
366
|
-
it 'returns an immutable WorkerCounts object' do
|
367
|
-
counts = subject.count
|
368
|
-
counts.should be_a(Supervisor::WorkerCounts)
|
369
|
-
|
370
|
-
lambda {
|
371
|
-
counts.specs += 1
|
372
|
-
}.should raise_error(RuntimeError)
|
373
|
-
end
|
374
|
-
|
375
|
-
it 'returns the total worker count as #specs' do
|
376
|
-
subject.count.specs.should eq 0
|
377
|
-
|
378
|
-
3.times do
|
379
|
-
subject.add_worker(worker_class.new, type: :worker)
|
380
|
-
subject.add_worker(worker_class.new, type: :supervisor)
|
381
|
-
end
|
382
|
-
|
383
|
-
subject.count.specs.should eq 6
|
384
|
-
end
|
385
|
-
|
386
|
-
it 'returns the count of all children marked as :supervisor as #supervisors' do
|
387
|
-
subject.count.supervisors.should eq 0
|
388
|
-
|
389
|
-
3.times do
|
390
|
-
subject.add_worker(worker_class.new, type: :worker)
|
391
|
-
subject.add_worker(worker_class.new, type: :supervisor)
|
392
|
-
end
|
393
|
-
|
394
|
-
subject.count.supervisors.should eq 3
|
395
|
-
end
|
396
|
-
|
397
|
-
it 'returns the count of all children marked as :worker as #workers' do
|
398
|
-
subject.count.workers.should eq 0
|
399
|
-
|
400
|
-
3.times do
|
401
|
-
subject.add_worker(worker_class.new, type: :worker)
|
402
|
-
subject.add_worker(worker_class.new, type: :supervisor)
|
403
|
-
end
|
404
|
-
|
405
|
-
subject.count.workers.should eq 3
|
406
|
-
end
|
407
|
-
|
408
|
-
it 'returns the count of all active workers as #active' do
|
409
|
-
busy_supervisor.count.active.should eq 0
|
410
|
-
busy_supervisor.run!
|
411
|
-
sleep(0.5)
|
412
|
-
|
413
|
-
busy_supervisor.count.active.should eq active_count
|
414
|
-
end
|
415
|
-
|
416
|
-
it 'returns the count of all sleeping workers as #sleeping' do
|
417
|
-
busy_supervisor.count.sleeping.should eq 0
|
418
|
-
busy_supervisor.run!
|
419
|
-
sleep(0.5)
|
420
|
-
|
421
|
-
busy_supervisor.count.sleeping.should eq sleeping_count
|
422
|
-
end
|
423
|
-
|
424
|
-
it 'returns the count of all running workers as #running' do
|
425
|
-
busy_supervisor.count.running.should eq 0
|
426
|
-
busy_supervisor.run!
|
427
|
-
sleep(0.5)
|
428
|
-
|
429
|
-
busy_supervisor.count.running.should eq running_count
|
430
|
-
end
|
431
|
-
|
432
|
-
it 'returns the count of all aborting workers as #aborting' do
|
433
|
-
busy_supervisor.count.aborting.should eq 0
|
434
|
-
|
435
|
-
count = Supervisor::WorkerCounts.new(5, 0, 5)
|
436
|
-
count.status = %w[aborting run aborting false aborting]
|
437
|
-
count.aborting.should eq 3
|
438
|
-
end
|
439
|
-
|
440
|
-
it 'returns the count of all stopped workers as #stopped' do
|
441
|
-
busy_supervisor.count.stopped.should eq total_count
|
442
|
-
busy_supervisor.run!
|
443
|
-
stoppers.each{|stopper| stopper.latch.wait(1) }
|
444
|
-
sleep(0.1)
|
445
|
-
|
446
|
-
busy_supervisor.count.stopped.should eq stopped_count
|
447
|
-
end
|
448
|
-
|
449
|
-
it 'returns the count of all workers terminated by exception as #abend' do
|
450
|
-
busy_supervisor.count.abend.should eq 0
|
451
|
-
busy_supervisor.run!
|
452
|
-
stoppers.each{|stopper| stopper.latch.wait(1) }
|
453
|
-
sleep(0.1)
|
454
|
-
|
455
|
-
busy_supervisor.count.abend.should eq abend_count
|
456
|
-
end
|
457
|
-
end
|
458
|
-
|
459
|
-
context '#current_restart_count' do
|
460
|
-
|
461
|
-
it 'is zero for a new Supervisor' do
|
462
|
-
subject.current_restart_count.should eq 0
|
463
|
-
end
|
464
|
-
|
465
|
-
it 'returns the number of worker restarts' do
|
466
|
-
worker = error_class.new
|
467
|
-
supervisor = Supervisor.new(monitor_interval: 0.1)
|
468
|
-
supervisor.add_worker(worker)
|
469
|
-
supervisor.run!
|
470
|
-
sleep(0.3)
|
471
|
-
supervisor.current_restart_count.should > 0
|
472
|
-
supervisor.stop
|
473
|
-
end
|
474
|
-
|
475
|
-
it 'resets to zero on #stop' do
|
476
|
-
worker = error_class.new
|
477
|
-
supervisor = Supervisor.new(monitor_interval: 0.1)
|
478
|
-
supervisor.add_worker(worker)
|
479
|
-
supervisor.run!
|
480
|
-
sleep(0.3)
|
481
|
-
supervisor.stop
|
482
|
-
sleep(0.1)
|
483
|
-
supervisor.current_restart_count.should eq 0
|
484
|
-
end
|
485
|
-
end
|
486
|
-
|
487
|
-
context '#add_worker' do
|
488
|
-
|
489
|
-
it 'adds the worker when stopped' do
|
490
|
-
subject.add_worker(worker)
|
491
|
-
subject.length.should == 1
|
492
|
-
end
|
493
|
-
|
494
|
-
it 'runs the worker when the supervisor is running' do
|
495
|
-
worker = worker_class.new
|
496
|
-
worker.start_count.to_i.should eq 0
|
497
|
-
subject.run!
|
498
|
-
sleep(0.1)
|
499
|
-
subject.add_worker(worker).should be_true
|
500
|
-
sleep(0.1)
|
501
|
-
worker.start_count.should >= 1
|
502
|
-
end
|
503
|
-
|
504
|
-
it 'rejects a worker without the :runnable behavior' do
|
505
|
-
subject.add_worker('bogus worker')
|
506
|
-
subject.length.should == 0
|
507
|
-
end
|
508
|
-
|
509
|
-
it 'sets the restart type to the given value' do
|
510
|
-
subject.add_worker(worker_class.new, restart: :temporary)
|
511
|
-
worker = subject.instance_variable_get(:@workers).first
|
512
|
-
worker.restart.should eq :temporary
|
513
|
-
end
|
514
|
-
|
515
|
-
it 'sets the restart type to :permanent when none given' do
|
516
|
-
subject.add_worker(worker_class.new)
|
517
|
-
worker = subject.instance_variable_get(:@workers).first
|
518
|
-
worker.restart.should eq :permanent
|
519
|
-
end
|
520
|
-
|
521
|
-
it 'raises an exception when given an invalid restart type' do
|
522
|
-
lambda {
|
523
|
-
subject.add_worker(worker_class.new, restart: :bogus)
|
524
|
-
}.should raise_error(ArgumentError)
|
525
|
-
end
|
526
|
-
|
527
|
-
it 'sets the child type to the given value' do
|
528
|
-
subject.add_worker(worker_class.new, type: :supervisor)
|
529
|
-
worker = subject.instance_variable_get(:@workers).first
|
530
|
-
worker.type.should eq :supervisor
|
531
|
-
end
|
532
|
-
|
533
|
-
it 'sets the worker type to :worker when none given' do
|
534
|
-
subject.add_worker(worker_class.new)
|
535
|
-
worker = subject.instance_variable_get(:@workers).first
|
536
|
-
worker.type.should eq :worker
|
537
|
-
end
|
538
|
-
|
539
|
-
it 'sets the worker type to :supervisor when #is_a? Supervisor' do
|
540
|
-
subject.add_worker(Supervisor.new)
|
541
|
-
worker = subject.instance_variable_get(:@workers).first
|
542
|
-
worker.type.should eq :supervisor
|
543
|
-
end
|
544
|
-
|
545
|
-
it 'raises an exception when given an invalid restart type' do
|
546
|
-
lambda {
|
547
|
-
subject.add_worker(worker_class.new, type: :bogus)
|
548
|
-
}.should raise_error(ArgumentError)
|
549
|
-
end
|
550
|
-
|
551
|
-
it 'returns an object id when a worker is accepted' do
|
552
|
-
worker_id = subject.add_worker(worker)
|
553
|
-
worker_id.should be_a(Integer)
|
554
|
-
first = subject.instance_variable_get(:@workers).first
|
555
|
-
worker_id.should eq first.object_id
|
556
|
-
end
|
557
|
-
|
558
|
-
it 'returns nil when a worker is not accepted' do
|
559
|
-
subject.add_worker('bogus worker').should be_nil
|
560
|
-
end
|
561
|
-
end
|
562
|
-
|
563
|
-
context '#add_workers' do
|
564
|
-
|
565
|
-
it 'calls #add_worker once for each worker' do
|
566
|
-
workers = 5.times.collect{ worker_class.new }
|
567
|
-
workers.each do |worker|
|
568
|
-
subject.should_receive(:add_worker).once.with(worker, anything())
|
569
|
-
end
|
570
|
-
subject.add_workers(workers)
|
571
|
-
end
|
572
|
-
|
573
|
-
it 'passes the options hash to each #add_worker call' do
|
574
|
-
options = {
|
575
|
-
restart: :permanent,
|
576
|
-
type: :worker
|
577
|
-
}
|
578
|
-
workers = 5.times.collect{ worker_class.new }
|
579
|
-
workers.each do |worker|
|
580
|
-
subject.should_receive(:add_worker).once.with(anything(), options)
|
581
|
-
end
|
582
|
-
subject.add_workers(workers, options)
|
583
|
-
end
|
584
|
-
|
585
|
-
it 'returns an array of object identifiers' do
|
586
|
-
workers = 5.times.collect{ worker_class.new }
|
587
|
-
context = subject.add_workers(workers)
|
588
|
-
context.size.should == 5
|
589
|
-
context.each do |wc|
|
590
|
-
wc.should be_a(Fixnum)
|
591
|
-
end
|
592
|
-
end
|
593
|
-
end
|
594
|
-
|
595
|
-
context '#remove_worker' do
|
596
|
-
|
597
|
-
it 'returns false if the worker is running' do
|
598
|
-
id = subject.add_worker(sleeper_class.new)
|
599
|
-
subject.run!
|
600
|
-
sleep(0.1)
|
601
|
-
subject.remove_worker(id).should be_false
|
602
|
-
end
|
603
|
-
|
604
|
-
it 'returns nil if the worker is not found' do
|
605
|
-
subject.run!
|
606
|
-
sleep(0.1)
|
607
|
-
subject.remove_worker(1234).should be_nil
|
608
|
-
end
|
609
|
-
|
610
|
-
it 'returns the worker on success' do
|
611
|
-
worker = error_class.new
|
612
|
-
supervisor = Supervisor.new(monitor_interval: 60)
|
613
|
-
id = supervisor.add_worker(worker)
|
614
|
-
supervisor.run!
|
615
|
-
sleep(0.1)
|
616
|
-
supervisor.remove_worker(id).should eq worker
|
617
|
-
supervisor.stop
|
618
|
-
end
|
619
|
-
|
620
|
-
it 'removes the worker from the supervisor on success' do
|
621
|
-
worker = error_class.new
|
622
|
-
supervisor = Supervisor.new(monitor_interval: 60)
|
623
|
-
id = supervisor.add_worker(worker)
|
624
|
-
supervisor.length.should == 1
|
625
|
-
supervisor.run!
|
626
|
-
sleep(0.1)
|
627
|
-
supervisor.remove_worker(id)
|
628
|
-
supervisor.length.should == 0
|
629
|
-
supervisor.stop
|
630
|
-
end
|
631
|
-
end
|
632
|
-
|
633
|
-
context '#stop_worker' do
|
634
|
-
|
635
|
-
it 'returns true if the supervisor is not running' do
|
636
|
-
worker = worker_class.new
|
637
|
-
id = subject.add_worker(worker)
|
638
|
-
subject.stop_worker(id).should be_true
|
639
|
-
end
|
640
|
-
|
641
|
-
it 'returns nil if the worker is not found' do
|
642
|
-
worker = sleeper_class.new
|
643
|
-
id = subject.add_worker(worker)
|
644
|
-
subject.run!
|
645
|
-
sleep(0.1)
|
646
|
-
subject.stop_worker(1234).should be_nil
|
647
|
-
end
|
648
|
-
|
649
|
-
it 'returns true on success' do
|
650
|
-
worker = sleeper_class.new
|
651
|
-
id = subject.add_worker(worker)
|
652
|
-
subject.run!
|
653
|
-
sleep(0.1)
|
654
|
-
worker.should_receive(:stop).at_least(1).times.and_return(true)
|
655
|
-
subject.stop_worker(id).should be_true
|
656
|
-
end
|
657
|
-
|
658
|
-
it 'deletes the worker if it is :temporary' do
|
659
|
-
worker = sleeper_class.new
|
660
|
-
id = subject.add_worker(worker, restart: :temporary)
|
661
|
-
subject.size.should eq 1
|
662
|
-
subject.run!
|
663
|
-
sleep(0.1)
|
664
|
-
subject.stop_worker(id).should be_true
|
665
|
-
subject.size.should eq 0
|
666
|
-
end
|
667
|
-
|
668
|
-
it 'does not implicitly restart the worker' do
|
669
|
-
supervisor = Supervisor.new(monitor_interval: 0.1)
|
670
|
-
worker = runner_class.new
|
671
|
-
id = supervisor.add_worker(worker, restart: :permanent)
|
672
|
-
supervisor.run!
|
673
|
-
sleep(0.1)
|
674
|
-
supervisor.stop_worker(id)
|
675
|
-
sleep(0.5)
|
676
|
-
supervisor.stop
|
677
|
-
worker.start_count.should eq 1
|
678
|
-
end
|
679
|
-
end
|
680
|
-
|
681
|
-
context '#start_worker' do
|
682
|
-
|
683
|
-
it 'returns false if the supervisor is not running' do
|
684
|
-
worker = worker_class.new
|
685
|
-
id = subject.add_worker(worker)
|
686
|
-
subject.start_worker(id).should be_false
|
687
|
-
end
|
688
|
-
|
689
|
-
it 'returns nil if the worker is not found' do
|
690
|
-
subject.run!
|
691
|
-
sleep(0.1)
|
692
|
-
subject.start_worker(1234).should be_nil
|
693
|
-
end
|
694
|
-
|
695
|
-
it 'starts the worker if not running' do
|
696
|
-
supervisor = Supervisor.new(monitor_interval: 60)
|
697
|
-
worker = error_class.new
|
698
|
-
id = supervisor.add_worker(worker)
|
699
|
-
supervisor.run!
|
700
|
-
sleep(0.1)
|
701
|
-
supervisor.start_worker(id)
|
702
|
-
sleep(0.1)
|
703
|
-
worker.start_count.should == 2
|
704
|
-
supervisor.stop
|
705
|
-
end
|
706
|
-
|
707
|
-
it 'returns true when the worker is successfully started' do
|
708
|
-
supervisor = Supervisor.new(monitor_interval: 60)
|
709
|
-
worker = error_class.new
|
710
|
-
id = supervisor.add_worker(worker)
|
711
|
-
supervisor.run!
|
712
|
-
sleep(0.1)
|
713
|
-
supervisor.start_worker(id).should be_true
|
714
|
-
supervisor.stop
|
715
|
-
end
|
716
|
-
|
717
|
-
it 'returns true if the worker was already running' do
|
718
|
-
supervisor = Supervisor.new(monitor_interval: 60)
|
719
|
-
worker = sleeper_class.new
|
720
|
-
id = supervisor.add_worker(worker)
|
721
|
-
supervisor.run!
|
722
|
-
sleep(0.1)
|
723
|
-
supervisor.start_worker(id).should be_true
|
724
|
-
worker.start_count.should == 1
|
725
|
-
supervisor.stop
|
726
|
-
end
|
727
|
-
end
|
728
|
-
|
729
|
-
context '#restart_worker' do
|
730
|
-
|
731
|
-
it 'returns false if the supervisor is not running' do
|
732
|
-
worker = worker_class.new
|
733
|
-
id = subject.add_worker(worker)
|
734
|
-
subject.restart_worker(id).should be_false
|
735
|
-
end
|
736
|
-
|
737
|
-
it 'returns nil if the worker is not found' do
|
738
|
-
subject.run!
|
739
|
-
sleep(0.1)
|
740
|
-
subject.restart_worker(1234).should be_nil
|
741
|
-
end
|
742
|
-
|
743
|
-
it 'returns false if the worker is :temporary' do
|
744
|
-
worker = worker_class.new
|
745
|
-
id = subject.add_worker(worker, restart: :temporary)
|
746
|
-
subject.run!
|
747
|
-
sleep(0.1)
|
748
|
-
subject.restart_worker(id).should be_false
|
749
|
-
end
|
750
|
-
|
751
|
-
it 'stops and then starts a worker that is running' do
|
752
|
-
worker = runner_class.new
|
753
|
-
id = subject.add_worker(worker)
|
754
|
-
subject.run!
|
755
|
-
sleep(0.1)
|
756
|
-
subject.restart_worker(id)
|
757
|
-
sleep(0.1)
|
758
|
-
worker.start_count.should == 2
|
759
|
-
worker.stop_count.should == 1
|
760
|
-
end
|
761
|
-
|
762
|
-
it 'returns true if the worker is running and is successfully restarted' do
|
763
|
-
worker = runner_class.new
|
764
|
-
id = subject.add_worker(worker)
|
765
|
-
subject.run!
|
766
|
-
sleep(0.1)
|
767
|
-
subject.restart_worker(id).should be_true
|
768
|
-
end
|
769
|
-
|
770
|
-
it 'starts a worker that is not running' do
|
771
|
-
worker = error_class.new
|
772
|
-
id = subject.add_worker(worker)
|
773
|
-
subject.run!
|
774
|
-
sleep(0.1)
|
775
|
-
subject.restart_worker(id)
|
776
|
-
sleep(0.1)
|
777
|
-
worker.start_count.should >= 2
|
778
|
-
end
|
779
|
-
|
780
|
-
it 'returns true if the worker is not running and is successfully started' do
|
781
|
-
worker = error_class.new
|
782
|
-
id = subject.add_worker(worker)
|
783
|
-
subject.run!
|
784
|
-
sleep(0.1)
|
785
|
-
subject.restart_worker(id).should be_true
|
786
|
-
end
|
787
|
-
end
|
788
|
-
|
789
|
-
context 'maximum restart frequency' do
|
790
|
-
|
791
|
-
context '#exceeded_max_restart_frequency?' do
|
792
|
-
|
793
|
-
# Normally I am very opposed to testing private methods
|
794
|
-
# but this functionality has proven extremely difficult to test.
|
795
|
-
# Geting the timing right is almost impossible. This is the
|
796
|
-
# best approach I could think of.
|
797
|
-
|
798
|
-
it 'increments the restart count on every call' do
|
799
|
-
subject.send(:exceeded_max_restart_frequency?)
|
800
|
-
subject.current_restart_count.should eq 1
|
801
|
-
|
802
|
-
subject.send(:exceeded_max_restart_frequency?)
|
803
|
-
subject.current_restart_count.should eq 2
|
804
|
-
|
805
|
-
subject.send(:exceeded_max_restart_frequency?)
|
806
|
-
subject.current_restart_count.should eq 3
|
807
|
-
end
|
808
|
-
|
809
|
-
it 'returns false when the restart count is lower than :max_restart' do
|
810
|
-
supervisor = Supervisor.new(max_restart: 5, max_time: 60)
|
811
|
-
|
812
|
-
Timecop.freeze do
|
813
|
-
4.times do
|
814
|
-
Timecop.travel(5)
|
815
|
-
supervisor.send(:exceeded_max_restart_frequency?).should be_false
|
816
|
-
end
|
817
|
-
|
818
|
-
Timecop.travel(5)
|
819
|
-
supervisor.send(:exceeded_max_restart_frequency?).should be_true
|
820
|
-
end
|
821
|
-
end
|
822
|
-
|
823
|
-
it 'returns false when the restart count is high but the time range is out of scope' do
|
824
|
-
supervisor = Supervisor.new(max_restart: 3, max_time: 8)
|
825
|
-
|
826
|
-
Timecop.freeze do
|
827
|
-
10.times do
|
828
|
-
Timecop.travel(5)
|
829
|
-
supervisor.send(:exceeded_max_restart_frequency?).should be_false
|
830
|
-
end
|
831
|
-
end
|
832
|
-
end
|
833
|
-
|
834
|
-
it 'returns true when the restart count is exceeded within the max time range' do
|
835
|
-
supervisor = Supervisor.new(max_restart: 2, max_time: 5)
|
836
|
-
Timecop.freeze do
|
837
|
-
supervisor.send(:exceeded_max_restart_frequency?).should be_false
|
838
|
-
Timecop.travel(1)
|
839
|
-
supervisor.send(:exceeded_max_restart_frequency?).should be_true
|
840
|
-
end
|
841
|
-
end
|
842
|
-
end
|
843
|
-
|
844
|
-
context 'restarts when true for strategy' do
|
845
|
-
|
846
|
-
specify ':one_for_one' do
|
847
|
-
supervisor = Supervisor.new(restart_strategy: :one_for_one,
|
848
|
-
monitor_interval: 0.1)
|
849
|
-
supervisor.add_worker(error_class.new)
|
850
|
-
supervisor.stub(:exceeded_max_restart_frequency?).once.and_return(true)
|
851
|
-
future = Concurrent::Future.execute{ supervisor.run }
|
852
|
-
future.value(1)
|
853
|
-
supervisor.should_not be_running
|
854
|
-
end
|
855
|
-
|
856
|
-
specify ':one_for_all' do
|
857
|
-
supervisor = Supervisor.new(restart_strategy: :one_for_all,
|
858
|
-
monitor_interval: 0.1)
|
859
|
-
supervisor.add_worker(error_class.new)
|
860
|
-
supervisor.should_receive(:exceeded_max_restart_frequency?).once.and_return(true)
|
861
|
-
future = Concurrent::Future.execute{ supervisor.run }
|
862
|
-
future.value(1)
|
863
|
-
supervisor.should_not be_running
|
864
|
-
end
|
865
|
-
|
866
|
-
specify ':rest_for_one' do
|
867
|
-
supervisor = Supervisor.new(restart_strategy: :rest_for_one,
|
868
|
-
monitor_interval: 0.1)
|
869
|
-
supervisor.add_worker(error_class.new)
|
870
|
-
supervisor.should_receive(:exceeded_max_restart_frequency?).once.and_return(true)
|
871
|
-
future = Concurrent::Future.execute{ supervisor.run }
|
872
|
-
future.value(1)
|
873
|
-
supervisor.should_not be_running
|
874
|
-
end
|
875
|
-
end
|
876
|
-
end
|
877
|
-
|
878
|
-
context 'restart strategies' do
|
879
|
-
|
880
|
-
context ':one_for_one' do
|
881
|
-
|
882
|
-
it 'restarts any worker that stops' do
|
883
|
-
|
884
|
-
workers = [
|
885
|
-
sleeper_class.new,
|
886
|
-
stopper_class.new,
|
887
|
-
sleeper_class.new
|
888
|
-
]
|
889
|
-
|
890
|
-
supervisor = Supervisor.new(strategy: :one_for_one, monitor_interval: 0.1)
|
891
|
-
workers.each{|worker| supervisor.add_worker(worker) }
|
892
|
-
|
893
|
-
supervisor.run!
|
894
|
-
sleep(1)
|
895
|
-
|
896
|
-
workers[0].start_count.should == 1
|
897
|
-
workers[1].start_count.should >= 2
|
898
|
-
workers[2].start_count.should == 1
|
899
|
-
|
900
|
-
supervisor.stop
|
901
|
-
end
|
902
|
-
|
903
|
-
it 'restarts any dead threads' do
|
904
|
-
|
905
|
-
workers = [
|
906
|
-
sleeper_class.new,
|
907
|
-
error_class.new,
|
908
|
-
sleeper_class.new
|
909
|
-
]
|
910
|
-
|
911
|
-
supervisor = Supervisor.new(strategy: :one_for_one, monitor_interval: 0.1)
|
912
|
-
workers.each{|worker| supervisor.add_worker(worker) }
|
913
|
-
|
914
|
-
supervisor.run!
|
915
|
-
sleep(1)
|
916
|
-
|
917
|
-
workers[0].start_count.should == 1
|
918
|
-
workers[1].start_count.should >= 2
|
919
|
-
workers[2].start_count.should == 1
|
920
|
-
|
921
|
-
supervisor.stop
|
922
|
-
end
|
923
|
-
end
|
924
|
-
|
925
|
-
context ':one_for_all' do
|
926
|
-
|
927
|
-
it 'restarts all workers when one stops' do
|
928
|
-
|
929
|
-
workers = [
|
930
|
-
sleeper_class.new,
|
931
|
-
stopper_class.new,
|
932
|
-
sleeper_class.new
|
933
|
-
]
|
934
|
-
|
935
|
-
supervisor = Supervisor.new(strategy: :one_for_all, monitor_interval: 0.1)
|
936
|
-
workers.each{|worker| supervisor.add_worker(worker) }
|
937
|
-
|
938
|
-
workers[0].should_receive(:stop).once.with(no_args())
|
939
|
-
workers[2].should_receive(:stop).once.with(no_args())
|
940
|
-
|
941
|
-
supervisor.run!
|
942
|
-
sleep(1)
|
943
|
-
workers.each{|worker| worker.start_count.should >= 2 }
|
944
|
-
|
945
|
-
supervisor.stop
|
946
|
-
end
|
947
|
-
|
948
|
-
it 'restarts all workers when one thread dies' do
|
949
|
-
|
950
|
-
workers = [
|
951
|
-
sleeper_class.new,
|
952
|
-
error_class.new,
|
953
|
-
sleeper_class.new
|
954
|
-
]
|
955
|
-
|
956
|
-
supervisor = Supervisor.new(strategy: :one_for_all, monitor_interval: 0.1)
|
957
|
-
workers.each{|worker| supervisor.add_worker(worker) }
|
958
|
-
|
959
|
-
workers[0].should_receive(:stop).once.with(no_args())
|
960
|
-
workers[2].should_receive(:stop).once.with(no_args())
|
961
|
-
|
962
|
-
supervisor.run!
|
963
|
-
sleep(1)
|
964
|
-
workers.each{|worker| worker.start_count.should >= 2 }
|
965
|
-
|
966
|
-
supervisor.stop
|
967
|
-
end
|
968
|
-
end
|
969
|
-
|
970
|
-
context ':rest_for_one' do
|
971
|
-
|
972
|
-
it 'restarts a stopped worker and all workers added after it' do
|
973
|
-
|
974
|
-
workers = [
|
975
|
-
sleeper_class.new,
|
976
|
-
stopper_class.new,
|
977
|
-
sleeper_class.new
|
978
|
-
]
|
979
|
-
|
980
|
-
supervisor = Supervisor.new(strategy: :rest_for_one, monitor_interval: 0.1)
|
981
|
-
workers.each{|worker| supervisor.add_worker(worker) }
|
982
|
-
|
983
|
-
workers[0].should_not_receive(:stop)
|
984
|
-
workers[2].should_receive(:stop).once.with(no_args())
|
985
|
-
|
986
|
-
supervisor.run!
|
987
|
-
sleep(1)
|
988
|
-
|
989
|
-
workers[0].start_count.should == 1
|
990
|
-
workers[1].start_count.should >= 2
|
991
|
-
workers[2].start_count.should >= 2
|
992
|
-
|
993
|
-
supervisor.stop
|
994
|
-
end
|
995
|
-
|
996
|
-
it 'restarts a dead worker thread and all workers added after it' do
|
997
|
-
|
998
|
-
workers = [
|
999
|
-
sleeper_class.new,
|
1000
|
-
error_class.new,
|
1001
|
-
sleeper_class.new
|
1002
|
-
]
|
1003
|
-
|
1004
|
-
supervisor = Supervisor.new(strategy: :rest_for_one, monitor_interval: 0.1)
|
1005
|
-
workers.each{|worker| supervisor.add_worker(worker) }
|
1006
|
-
|
1007
|
-
workers[0].should_not_receive(:stop)
|
1008
|
-
workers[2].should_receive(:stop).once.with(no_args())
|
1009
|
-
|
1010
|
-
supervisor.run!
|
1011
|
-
sleep(1)
|
1012
|
-
|
1013
|
-
workers[0].start_count.should == 1
|
1014
|
-
workers[1].start_count.should >= 2
|
1015
|
-
workers[2].start_count.should >= 2
|
1016
|
-
|
1017
|
-
supervisor.stop
|
1018
|
-
end
|
1019
|
-
end
|
1020
|
-
end
|
1021
|
-
|
1022
|
-
context 'child restart options' do
|
1023
|
-
|
1024
|
-
def worker_status(supervisor)
|
1025
|
-
worker = supervisor.instance_variable_get(:@workers).first
|
1026
|
-
return worker.thread.status
|
1027
|
-
end
|
1028
|
-
|
1029
|
-
specify ':permanent restarts on abend' do
|
1030
|
-
worker = error_class.new
|
1031
|
-
supervisor = Supervisor.new(monitor_interval: 0.1)
|
1032
|
-
supervisor.add_worker(worker, restart: :permanent)
|
1033
|
-
|
1034
|
-
supervisor.run!
|
1035
|
-
sleep(0.5)
|
1036
|
-
supervisor.stop
|
1037
|
-
|
1038
|
-
worker.start_count.should >= 1
|
1039
|
-
end
|
1040
|
-
|
1041
|
-
specify ':permanent restarts on normal stop' do
|
1042
|
-
worker = stopper_class.new(0.1)
|
1043
|
-
supervisor = Supervisor.new(monitor_interval: 0.1)
|
1044
|
-
supervisor.add_worker(worker, restart: :permanent)
|
1045
|
-
|
1046
|
-
supervisor.run!
|
1047
|
-
sleep(0.5)
|
1048
|
-
supervisor.stop
|
1049
|
-
|
1050
|
-
worker.start_count.should >= 1
|
1051
|
-
end
|
1052
|
-
|
1053
|
-
specify ':temporary does not restart on abend' do
|
1054
|
-
worker = error_class.new
|
1055
|
-
supervisor = Supervisor.new(monitor_interval: 0.1)
|
1056
|
-
supervisor.add_worker(worker, restart: :temporary)
|
1057
|
-
|
1058
|
-
supervisor.run!
|
1059
|
-
sleep(0.5)
|
1060
|
-
supervisor.stop
|
1061
|
-
|
1062
|
-
worker.start_count.should eq 1
|
1063
|
-
end
|
1064
|
-
|
1065
|
-
specify ':temporary does not restart on normal stop' do
|
1066
|
-
worker = stopper_class.new
|
1067
|
-
supervisor = Supervisor.new(monitor_interval: 0.1)
|
1068
|
-
supervisor.add_worker(worker, restart: :temporary)
|
1069
|
-
|
1070
|
-
supervisor.run!
|
1071
|
-
sleep(0.5)
|
1072
|
-
supervisor.stop
|
1073
|
-
|
1074
|
-
worker.start_count.should eq 1
|
1075
|
-
end
|
1076
|
-
|
1077
|
-
specify ':temporary is deleted on abend' do
|
1078
|
-
worker = error_class.new
|
1079
|
-
supervisor = Supervisor.new(monitor_interval: 0.1)
|
1080
|
-
supervisor.add_worker(worker, restart: :temporary)
|
1081
|
-
|
1082
|
-
supervisor.run!
|
1083
|
-
sleep(0.5)
|
1084
|
-
supervisor.stop
|
1085
|
-
|
1086
|
-
supervisor.size.should eq 0
|
1087
|
-
end
|
1088
|
-
|
1089
|
-
specify ':temporary is deleted on normal stop' do
|
1090
|
-
worker = stopper_class.new
|
1091
|
-
supervisor = Supervisor.new(monitor_interval: 0.1)
|
1092
|
-
supervisor.add_worker(worker, restart: :temporary)
|
1093
|
-
|
1094
|
-
supervisor.run!
|
1095
|
-
sleep(0.5)
|
1096
|
-
supervisor.stop
|
1097
|
-
|
1098
|
-
supervisor.size.should eq 0
|
1099
|
-
end
|
1100
|
-
|
1101
|
-
specify ':transient restarts on abend' do
|
1102
|
-
worker = error_class.new
|
1103
|
-
supervisor = Supervisor.new(monitor_interval: 0.1)
|
1104
|
-
supervisor.add_worker(worker, restart: :transient)
|
1105
|
-
|
1106
|
-
supervisor.run!
|
1107
|
-
sleep(0.5)
|
1108
|
-
supervisor.stop
|
1109
|
-
|
1110
|
-
worker.start_count.should >= 1
|
1111
|
-
end
|
1112
|
-
|
1113
|
-
specify ':transient does not restart on normal stop' do
|
1114
|
-
worker = stopper_class.new
|
1115
|
-
supervisor = Supervisor.new(monitor_interval: 0.1)
|
1116
|
-
supervisor.add_worker(worker, restart: :transient)
|
1117
|
-
|
1118
|
-
supervisor.run!
|
1119
|
-
sleep(0.5)
|
1120
|
-
supervisor.stop
|
1121
|
-
|
1122
|
-
worker.start_count.should eq 1
|
1123
|
-
end
|
1124
|
-
end
|
1125
|
-
|
1126
|
-
context 'supervision tree' do
|
1127
|
-
|
1128
|
-
specify do
|
1129
|
-
s1 = Supervisor.new(monitor_interval: 0.1)
|
1130
|
-
s2 = Supervisor.new(monitor_interval: 0.1)
|
1131
|
-
s3 = Supervisor.new(monitor_interval: 0.1)
|
1132
|
-
|
1133
|
-
workers = (1..3).collect{ sleeper_class.new }
|
1134
|
-
workers.each{|worker| s3.add_worker(worker)}
|
1135
|
-
|
1136
|
-
workers.each{|worker| worker.should_receive(:stop).at_least(1).times.with(no_args())}
|
1137
|
-
|
1138
|
-
s1.add_worker(s2)
|
1139
|
-
s2.add_worker(s3)
|
1140
|
-
|
1141
|
-
s1.run!
|
1142
|
-
sleep(0.2)
|
1143
|
-
|
1144
|
-
s1.stop
|
1145
|
-
sleep(0.2)
|
1146
|
-
end
|
1147
|
-
end
|
1148
|
-
end
|
1149
|
-
end
|