concurrent-ruby 0.2.2 → 0.3.0.pre.1
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 +45 -42
- data/lib/concurrent.rb +5 -6
- data/lib/concurrent/agent.rb +29 -33
- data/lib/concurrent/cached_thread_pool.rb +26 -105
- data/lib/concurrent/channel.rb +94 -0
- data/lib/concurrent/event.rb +8 -17
- data/lib/concurrent/executor.rb +68 -72
- data/lib/concurrent/fixed_thread_pool.rb +15 -83
- data/lib/concurrent/functions.rb +7 -22
- data/lib/concurrent/future.rb +29 -9
- data/lib/concurrent/null_thread_pool.rb +5 -2
- data/lib/concurrent/obligation.rb +6 -16
- data/lib/concurrent/promise.rb +9 -10
- data/lib/concurrent/runnable.rb +103 -0
- data/lib/concurrent/supervisor.rb +271 -44
- data/lib/concurrent/thread_pool.rb +112 -39
- data/lib/concurrent/version.rb +1 -1
- data/md/executor.md +9 -3
- data/md/goroutine.md +11 -9
- data/md/reactor.md +32 -0
- data/md/supervisor.md +43 -0
- data/spec/concurrent/agent_spec.rb +128 -51
- data/spec/concurrent/cached_thread_pool_spec.rb +33 -47
- data/spec/concurrent/channel_spec.rb +446 -0
- data/spec/concurrent/event_machine_defer_proxy_spec.rb +3 -1
- data/spec/concurrent/event_spec.rb +0 -19
- data/spec/concurrent/executor_spec.rb +167 -119
- data/spec/concurrent/fixed_thread_pool_spec.rb +40 -30
- data/spec/concurrent/functions_spec.rb +0 -20
- data/spec/concurrent/future_spec.rb +88 -0
- data/spec/concurrent/null_thread_pool_spec.rb +23 -2
- data/spec/concurrent/obligation_shared.rb +0 -5
- data/spec/concurrent/promise_spec.rb +9 -10
- data/spec/concurrent/runnable_shared.rb +62 -0
- data/spec/concurrent/runnable_spec.rb +233 -0
- data/spec/concurrent/supervisor_spec.rb +912 -47
- data/spec/concurrent/thread_pool_shared.rb +18 -31
- data/spec/spec_helper.rb +10 -3
- metadata +17 -23
- data/lib/concurrent/defer.rb +0 -65
- data/lib/concurrent/reactor.rb +0 -166
- data/lib/concurrent/reactor/drb_async_demux.rb +0 -83
- data/lib/concurrent/reactor/tcp_sync_demux.rb +0 -131
- data/lib/concurrent/utilities.rb +0 -32
- data/md/defer.md +0 -174
- data/spec/concurrent/defer_spec.rb +0 -199
- data/spec/concurrent/reactor/drb_async_demux_spec.rb +0 -196
- data/spec/concurrent/reactor/tcp_sync_demux_spec.rb +0 -410
- data/spec/concurrent/reactor_spec.rb +0 -364
- data/spec/concurrent/utilities_spec.rb +0 -74
@@ -5,8 +5,11 @@ module Concurrent
|
|
5
5
|
class NullThreadPool
|
6
6
|
behavior(:global_thread_pool)
|
7
7
|
|
8
|
-
def self.post(*args
|
9
|
-
Thread.new(*args
|
8
|
+
def self.post(*args)
|
9
|
+
Thread.new(*args) do
|
10
|
+
Thread.current.abort_on_exception = false
|
11
|
+
yield(*args)
|
12
|
+
end
|
10
13
|
return true
|
11
14
|
end
|
12
15
|
|
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'thread'
|
2
2
|
require 'timeout'
|
3
|
+
require 'functional'
|
3
4
|
|
4
|
-
require '
|
5
|
+
require 'concurrent/event'
|
5
6
|
|
6
7
|
behavior_info(:future,
|
7
8
|
state: 0,
|
@@ -42,26 +43,15 @@ module Concurrent
|
|
42
43
|
def pending?() return(@state == :pending); end
|
43
44
|
|
44
45
|
def value(timeout = nil)
|
45
|
-
|
46
|
-
|
47
|
-
elsif timeout.nil?
|
48
|
-
return mutex.synchronize { v = @value }
|
49
|
-
else
|
50
|
-
begin
|
51
|
-
return Timeout::timeout(timeout.to_f) {
|
52
|
-
mutex.synchronize { v = @value }
|
53
|
-
}
|
54
|
-
rescue Timeout::Error => ex
|
55
|
-
return nil
|
56
|
-
end
|
57
|
-
end
|
46
|
+
event.wait(timeout) unless timeout == 0 || @state != :pending
|
47
|
+
return @value
|
58
48
|
end
|
59
49
|
alias_method :deref, :value
|
60
50
|
|
61
51
|
protected
|
62
52
|
|
63
|
-
def
|
64
|
-
@
|
53
|
+
def event
|
54
|
+
@event ||= Event.new
|
65
55
|
end
|
66
56
|
end
|
67
57
|
end
|
data/lib/concurrent/promise.rb
CHANGED
@@ -2,7 +2,6 @@ require 'thread'
|
|
2
2
|
|
3
3
|
require 'concurrent/global_thread_pool'
|
4
4
|
require 'concurrent/obligation'
|
5
|
-
require 'concurrent/utilities'
|
6
5
|
|
7
6
|
module Concurrent
|
8
7
|
|
@@ -80,7 +79,7 @@ module Concurrent
|
|
80
79
|
# @param block [Proc] the block to call if the rescue is matched
|
81
80
|
#
|
82
81
|
# @return [self] so that additional chaining can occur
|
83
|
-
def rescue(clazz =
|
82
|
+
def rescue(clazz = nil, &block)
|
84
83
|
return self if fulfilled? || rescued? || ! block_given?
|
85
84
|
@lock.synchronize do
|
86
85
|
rescuer = Rescuer.new(clazz, block)
|
@@ -140,12 +139,12 @@ module Concurrent
|
|
140
139
|
# @private
|
141
140
|
def try_rescue(ex, *rescuers) # :nodoc:
|
142
141
|
rescuers = @rescuers if rescuers.empty?
|
143
|
-
rescuer = rescuers.find{|r| ex.is_a?(r.clazz) }
|
142
|
+
rescuer = rescuers.find{|r| r.clazz.nil? || ex.is_a?(r.clazz) }
|
144
143
|
if rescuer
|
145
144
|
rescuer.block.call(ex)
|
146
145
|
@rescued = true
|
147
146
|
end
|
148
|
-
rescue Exception =>
|
147
|
+
rescue Exception => ex
|
149
148
|
# supress
|
150
149
|
end
|
151
150
|
|
@@ -157,12 +156,12 @@ module Concurrent
|
|
157
156
|
loop do
|
158
157
|
current = lock.synchronize{ chain[index] }
|
159
158
|
unless current.rejected?
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
159
|
+
begin
|
160
|
+
result = current.on_fulfill(result)
|
161
|
+
rescue Exception => ex
|
162
|
+
current.on_reject(ex)
|
163
|
+
ensure
|
164
|
+
event.set
|
166
165
|
end
|
167
166
|
end
|
168
167
|
index += 1
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'thread'
|
2
|
+
require 'functional'
|
3
|
+
|
4
|
+
behavior_info(:runnable,
|
5
|
+
run: 0,
|
6
|
+
stop: 0,
|
7
|
+
running?: 0)
|
8
|
+
|
9
|
+
module Concurrent
|
10
|
+
|
11
|
+
module Running
|
12
|
+
|
13
|
+
class Context
|
14
|
+
attr_reader :runner, :thread
|
15
|
+
def initialize(runner)
|
16
|
+
@runner = runner
|
17
|
+
@thread = Thread.new(runner) do |runner|
|
18
|
+
Thread.abort_on_exception = false
|
19
|
+
runner.run
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.included(base)
|
25
|
+
|
26
|
+
def run!
|
27
|
+
return mutex.synchronize do
|
28
|
+
raise LifecycleError.new('already running') if @running
|
29
|
+
Context.new(self)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
protected
|
34
|
+
|
35
|
+
def mutex
|
36
|
+
@mutex ||= Mutex.new
|
37
|
+
end
|
38
|
+
|
39
|
+
public
|
40
|
+
|
41
|
+
class << base
|
42
|
+
|
43
|
+
def run!(*args, &block)
|
44
|
+
runner = self.new(*args, &block)
|
45
|
+
return Context.new(runner)
|
46
|
+
rescue => ex
|
47
|
+
return nil
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
module Runnable
|
54
|
+
|
55
|
+
behavior(:runnable)
|
56
|
+
|
57
|
+
LifecycleError = Class.new(StandardError)
|
58
|
+
|
59
|
+
def self.included(base)
|
60
|
+
base.send(:include, Running)
|
61
|
+
end
|
62
|
+
|
63
|
+
def run
|
64
|
+
mutex.synchronize do
|
65
|
+
raise LifecycleError.new('already running') if @running
|
66
|
+
raise LifecycleError.new('#on_task not implemented') unless self.respond_to?(:on_task, true)
|
67
|
+
on_run if respond_to?(:on_run, true)
|
68
|
+
@running = true
|
69
|
+
end
|
70
|
+
|
71
|
+
loop do
|
72
|
+
break unless @running
|
73
|
+
on_task
|
74
|
+
break unless @running
|
75
|
+
Thread.pass
|
76
|
+
end
|
77
|
+
|
78
|
+
after_run if respond_to?(:after_run, true)
|
79
|
+
return true
|
80
|
+
rescue LifecycleError => ex
|
81
|
+
@running = false
|
82
|
+
raise ex
|
83
|
+
rescue => ex
|
84
|
+
@running = false
|
85
|
+
return false
|
86
|
+
end
|
87
|
+
|
88
|
+
def stop
|
89
|
+
return true unless @running
|
90
|
+
mutex.synchronize do
|
91
|
+
@running = false
|
92
|
+
on_stop if respond_to?(:on_stop, true)
|
93
|
+
end
|
94
|
+
return true
|
95
|
+
rescue => ex
|
96
|
+
return false
|
97
|
+
end
|
98
|
+
|
99
|
+
def running?
|
100
|
+
return @running == true
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -1,71 +1,134 @@
|
|
1
1
|
require 'thread'
|
2
2
|
require 'functional'
|
3
3
|
|
4
|
-
|
5
|
-
run: 0,
|
6
|
-
stop: 0,
|
7
|
-
running?: 0)
|
4
|
+
require 'concurrent/runnable'
|
8
5
|
|
9
6
|
module Concurrent
|
10
7
|
|
11
8
|
class Supervisor
|
12
9
|
|
10
|
+
behavior(:runnable)
|
11
|
+
|
13
12
|
DEFAULT_MONITOR_INTERVAL = 1
|
13
|
+
RESTART_STRATEGIES = [:one_for_one, :one_for_all, :rest_for_one]
|
14
|
+
DEFAULT_MAX_RESTART = 5
|
15
|
+
DEFAULT_MAX_TIME = 60
|
14
16
|
|
15
|
-
|
17
|
+
CHILD_TYPES = [:worker, :supervisor]
|
18
|
+
CHILD_RESTART_OPTIONS = [:permanent, :transient, :temporary]
|
16
19
|
|
17
|
-
|
20
|
+
MaxRestartFrequencyError = Class.new(StandardError)
|
21
|
+
|
22
|
+
WorkerContext = Struct.new(:worker, :type, :restart) do
|
23
|
+
attr_accessor :thread
|
24
|
+
attr_accessor :terminated
|
25
|
+
def alive?() return thread && thread.alive?; end
|
26
|
+
def needs_restart?
|
27
|
+
return false if thread && thread.alive?
|
28
|
+
return false if terminated == true
|
29
|
+
case self.restart
|
30
|
+
when :permanent
|
31
|
+
return true
|
32
|
+
when :transient
|
33
|
+
return thread.nil? || thread.status.nil?
|
34
|
+
else #when :temporary
|
35
|
+
return false
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
WorkerCounts = Struct.new(:specs, :supervisors, :workers) do
|
41
|
+
attr_accessor :status
|
42
|
+
def add(context)
|
43
|
+
self.specs += 1
|
44
|
+
self.supervisors += 1 if context.type == :supervisor
|
45
|
+
self.workers += 1 if context.type == :worker
|
46
|
+
end
|
47
|
+
def active() sleeping + running + aborting end;
|
48
|
+
def sleeping() @status.reduce(0){|x, s| x += (s == 'sleep' ? 1 : 0) } end;
|
49
|
+
def running() @status.reduce(0){|x, s| x += (s == 'run' ? 1 : 0) } end;
|
50
|
+
def aborting() @status.reduce(0){|x, s| x += (s == 'aborting' ? 1 : 0) } end;
|
51
|
+
def stopped() @status.reduce(0){|x, s| x += (s == false ? 1 : 0) } end;
|
52
|
+
def abend() @status.reduce(0){|x, s| x += (s.nil? ? 1 : 0) } end;
|
53
|
+
end
|
18
54
|
|
19
55
|
attr_reader :monitor_interval
|
56
|
+
attr_reader :restart_strategy
|
57
|
+
attr_reader :max_restart
|
58
|
+
attr_reader :max_time
|
59
|
+
|
60
|
+
alias_method :strategy, :restart_strategy
|
61
|
+
alias_method :max_r, :max_restart
|
62
|
+
alias_method :max_t, :max_time
|
20
63
|
|
21
64
|
def initialize(opts = {})
|
65
|
+
@restart_strategy = opts[:restart_strategy] || opts[:strategy] || :one_for_one
|
66
|
+
@monitor_interval = (opts[:monitor_interval] || DEFAULT_MONITOR_INTERVAL).to_f
|
67
|
+
@max_restart = (opts[:max_restart] || opts[:max_r] || DEFAULT_MAX_RESTART).to_i
|
68
|
+
@max_time = (opts[:max_time] || opts[:max_t] || DEFAULT_MAX_TIME).to_i
|
69
|
+
|
70
|
+
raise ArgumentError.new(":#{@restart_strategy} is not a valid restart strategy") unless RESTART_STRATEGIES.include?(@restart_strategy)
|
71
|
+
raise ArgumentError.new(':monitor_interval must be greater than zero') unless @monitor_interval > 0.0
|
72
|
+
raise ArgumentError.new(':max_restart must be greater than zero') unless @max_restart > 0
|
73
|
+
raise ArgumentError.new(':max_time must be greater than zero') unless @max_time > 0
|
74
|
+
|
75
|
+
@running = false
|
22
76
|
@mutex = Mutex.new
|
23
77
|
@workers = []
|
24
|
-
@running = false
|
25
78
|
@monitor = nil
|
26
|
-
|
79
|
+
|
80
|
+
@count = WorkerCounts.new(0, 0, 0)
|
81
|
+
@restart_times = []
|
82
|
+
|
27
83
|
add_worker(opts[:worker]) unless opts[:worker].nil?
|
84
|
+
add_workers(opts[:workers]) unless opts[:workers].nil?
|
28
85
|
end
|
29
86
|
|
30
87
|
def run!
|
31
|
-
raise StandardError.new('already running') if running?
|
32
88
|
@mutex.synchronize do
|
89
|
+
raise StandardError.new('already running') if @running
|
33
90
|
@running = true
|
34
|
-
@monitor = Thread.new
|
35
|
-
|
91
|
+
@monitor = Thread.new do
|
92
|
+
Thread.current.abort_on_exception = false
|
93
|
+
monitor
|
94
|
+
end
|
36
95
|
end
|
37
96
|
Thread.pass
|
38
97
|
end
|
39
98
|
|
40
99
|
def run
|
41
|
-
|
42
|
-
|
100
|
+
@mutex.synchronize do
|
101
|
+
raise StandardError.new('already running') if @running
|
102
|
+
@running = true
|
103
|
+
end
|
43
104
|
monitor
|
105
|
+
return true
|
44
106
|
end
|
45
107
|
|
46
108
|
def stop
|
47
|
-
return true unless running
|
48
|
-
@running = false
|
109
|
+
return true unless @running
|
49
110
|
@mutex.synchronize do
|
50
|
-
|
51
|
-
@monitor
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
begin
|
56
|
-
context.worker.stop
|
57
|
-
Thread.pass
|
58
|
-
rescue Exception => ex
|
59
|
-
# suppress
|
60
|
-
ensure
|
61
|
-
Thread.kill(context.thread) unless context.thread.nil?
|
111
|
+
@running = false
|
112
|
+
unless @monitor.nil?
|
113
|
+
@monitor.run if @monitor.status == 'sleep'
|
114
|
+
if @monitor.join(0.1).nil?
|
115
|
+
@monitor.kill
|
62
116
|
end
|
117
|
+
@monitor = nil
|
118
|
+
end
|
119
|
+
@restart_times.clear
|
120
|
+
|
121
|
+
@workers.length.times do |i|
|
122
|
+
context = @workers[-1-i]
|
123
|
+
terminate_worker(context)
|
63
124
|
end
|
125
|
+
prune_workers
|
64
126
|
end
|
127
|
+
return true
|
65
128
|
end
|
66
129
|
|
67
130
|
def running?
|
68
|
-
return @running
|
131
|
+
return @running == true
|
69
132
|
end
|
70
133
|
|
71
134
|
def length
|
@@ -73,33 +136,197 @@ module Concurrent
|
|
73
136
|
end
|
74
137
|
alias_method :size, :length
|
75
138
|
|
76
|
-
def
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
}
|
83
|
-
|
139
|
+
def current_restart_count
|
140
|
+
return @restart_times.length
|
141
|
+
end
|
142
|
+
|
143
|
+
def count
|
144
|
+
return @mutex.synchronize do
|
145
|
+
@count.status = @workers.collect{|w| w.thread ? w.thread.status : false }
|
146
|
+
@count.dup.freeze
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def add_worker(worker, opts = {})
|
151
|
+
return nil if worker.nil? || ! worker.behaves_as?(:runnable)
|
152
|
+
return @mutex.synchronize {
|
153
|
+
restart = opts[:restart] || :permanent
|
154
|
+
type = opts[:type] || (worker.is_a?(Supervisor) ? :supervisor : nil) || :worker
|
155
|
+
raise ArgumentError.new(":#{restart} is not a valid restart option") unless CHILD_RESTART_OPTIONS.include?(restart)
|
156
|
+
raise ArgumentError.new(":#{type} is not a valid child type") unless CHILD_TYPES.include?(type)
|
157
|
+
context = WorkerContext.new(worker, type, restart)
|
158
|
+
@workers << context
|
159
|
+
@count.add(context)
|
160
|
+
worker.run if running?
|
161
|
+
context.object_id
|
162
|
+
}
|
163
|
+
end
|
164
|
+
alias_method :add_child, :add_worker
|
165
|
+
|
166
|
+
def add_workers(workers, opts = {})
|
167
|
+
return workers.collect do |worker|
|
168
|
+
add_worker(worker, opts)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
alias_method :add_children, :add_workers
|
172
|
+
|
173
|
+
def remove_worker(worker_id)
|
174
|
+
return @mutex.synchronize do
|
175
|
+
index, context = find_worker(worker_id)
|
176
|
+
break(nil) if context.nil?
|
177
|
+
break(false) if context.alive?
|
178
|
+
@workers.delete_at(index)
|
179
|
+
context.worker
|
180
|
+
end
|
181
|
+
end
|
182
|
+
alias_method :remove_child, :remove_worker
|
183
|
+
|
184
|
+
def stop_worker(worker_id)
|
185
|
+
return true unless running?
|
186
|
+
return @mutex.synchronize do
|
187
|
+
index, context = find_worker(worker_id)
|
188
|
+
break(nil) if index.nil?
|
189
|
+
context.terminated = true
|
190
|
+
terminate_worker(context)
|
191
|
+
@workers.delete_at(index) if @workers[index].restart == :temporary
|
192
|
+
true
|
193
|
+
end
|
194
|
+
end
|
195
|
+
alias_method :stop_child, :stop_worker
|
196
|
+
|
197
|
+
def start_worker(worker_id)
|
198
|
+
return false unless running?
|
199
|
+
return @mutex.synchronize do
|
200
|
+
index, context = find_worker(worker_id)
|
201
|
+
break(nil) if context.nil?
|
202
|
+
context.terminated = false
|
203
|
+
run_worker(context) unless context.alive?
|
204
|
+
true
|
84
205
|
end
|
85
206
|
end
|
207
|
+
alias_method :start_child, :start_worker
|
208
|
+
|
209
|
+
def restart_worker(worker_id)
|
210
|
+
return false unless running?
|
211
|
+
return @mutex.synchronize do
|
212
|
+
index, context = find_worker(worker_id)
|
213
|
+
break(nil) if context.nil?
|
214
|
+
break(false) if context.restart == :temporary
|
215
|
+
context.terminated = false
|
216
|
+
terminate_worker(context)
|
217
|
+
run_worker(context)
|
218
|
+
true
|
219
|
+
end
|
220
|
+
end
|
221
|
+
alias_method :restart_child, :restart_worker
|
86
222
|
|
87
223
|
private
|
88
224
|
|
89
225
|
def monitor
|
226
|
+
@workers.each{|context| run_worker(context)}
|
90
227
|
loop do
|
228
|
+
sleep(@monitor_interval)
|
229
|
+
break unless running?
|
91
230
|
@mutex.synchronize do
|
92
|
-
|
93
|
-
|
94
|
-
context.thread = Thread.new{ context.worker.run }
|
95
|
-
context.thread.abort_on_exception = false
|
96
|
-
end
|
97
|
-
end
|
231
|
+
prune_workers
|
232
|
+
self.send(@restart_strategy)
|
98
233
|
end
|
99
234
|
break unless running?
|
100
|
-
sleep(@monitor_interval)
|
101
|
-
break unless running?
|
102
235
|
end
|
236
|
+
rescue MaxRestartFrequencyError => ex
|
237
|
+
stop
|
238
|
+
end
|
239
|
+
|
240
|
+
def run_worker(context)
|
241
|
+
context.thread = Thread.new do
|
242
|
+
Thread.current.abort_on_exception = false
|
243
|
+
context.worker.run
|
244
|
+
end
|
245
|
+
return context
|
103
246
|
end
|
247
|
+
|
248
|
+
def terminate_worker(context)
|
249
|
+
if context.alive?
|
250
|
+
context.worker.stop
|
251
|
+
Thread.pass
|
252
|
+
end
|
253
|
+
rescue Exception => ex
|
254
|
+
begin
|
255
|
+
Thread.kill(context.thread)
|
256
|
+
rescue
|
257
|
+
# suppress
|
258
|
+
end
|
259
|
+
ensure
|
260
|
+
context.thread = nil
|
261
|
+
end
|
262
|
+
|
263
|
+
def prune_workers
|
264
|
+
@workers.delete_if{|w| w.restart == :temporary && ! w.alive? }
|
265
|
+
end
|
266
|
+
|
267
|
+
def find_worker(worker_id)
|
268
|
+
index = @workers.find_index{|worker| worker.object_id == worker_id}
|
269
|
+
if index.nil?
|
270
|
+
return [nil, nil]
|
271
|
+
else
|
272
|
+
return [index, @workers[index]]
|
273
|
+
end
|
274
|
+
end
|
275
|
+
|
276
|
+
def exceeded_max_restart_frequency?
|
277
|
+
@restart_times.unshift(Time.now.to_i)
|
278
|
+
diff = delta(@restart_times.first, @restart_times.last)
|
279
|
+
if @restart_times.length >= @max_restart && diff <= @max_time
|
280
|
+
return true
|
281
|
+
elsif diff >= @max_time
|
282
|
+
@restart_times.pop
|
283
|
+
end
|
284
|
+
return false
|
285
|
+
end
|
286
|
+
|
287
|
+
#----------------------------------------------------------------
|
288
|
+
# restart strategies
|
289
|
+
|
290
|
+
def one_for_one
|
291
|
+
@workers.each do |context|
|
292
|
+
if context.needs_restart?
|
293
|
+
raise MaxRestartFrequencyError if exceeded_max_restart_frequency?
|
294
|
+
run_worker(context)
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
|
299
|
+
def one_for_all
|
300
|
+
restart = false
|
301
|
+
|
302
|
+
restart = @workers.each do |context|
|
303
|
+
if context.needs_restart?
|
304
|
+
raise MaxRestartFrequencyError if exceeded_max_restart_frequency?
|
305
|
+
break(true)
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
if restart
|
310
|
+
@workers.each do |context|
|
311
|
+
terminate_worker(context)
|
312
|
+
end
|
313
|
+
@workers.each{|context| run_worker(context)}
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
def rest_for_one
|
318
|
+
restart = false
|
319
|
+
|
320
|
+
@workers.each do |context|
|
321
|
+
if restart
|
322
|
+
terminate_worker(context)
|
323
|
+
elsif context.needs_restart?
|
324
|
+
raise MaxRestartFrequencyError if exceeded_max_restart_frequency?
|
325
|
+
restart = true
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
one_for_one if restart
|
104
330
|
end
|
105
331
|
end
|
332
|
+
end
|