concurrent-ruby 0.7.0.rc0-x86-linux

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +15 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +166 -0
  4. data/ext/concurrent_ruby_ext/atomic_reference.c +78 -0
  5. data/ext/concurrent_ruby_ext/atomic_reference.h +12 -0
  6. data/ext/concurrent_ruby_ext/extconf.rb +59 -0
  7. data/ext/concurrent_ruby_ext/rb_concurrent.c +28 -0
  8. data/lib/concurrent.rb +45 -0
  9. data/lib/concurrent/actress.rb +221 -0
  10. data/lib/concurrent/actress/ad_hoc.rb +20 -0
  11. data/lib/concurrent/actress/context.rb +98 -0
  12. data/lib/concurrent/actress/core.rb +228 -0
  13. data/lib/concurrent/actress/core_delegations.rb +42 -0
  14. data/lib/concurrent/actress/envelope.rb +41 -0
  15. data/lib/concurrent/actress/errors.rb +14 -0
  16. data/lib/concurrent/actress/reference.rb +64 -0
  17. data/lib/concurrent/actress/type_check.rb +48 -0
  18. data/lib/concurrent/agent.rb +232 -0
  19. data/lib/concurrent/async.rb +319 -0
  20. data/lib/concurrent/atomic.rb +46 -0
  21. data/lib/concurrent/atomic/atomic_boolean.rb +157 -0
  22. data/lib/concurrent/atomic/atomic_fixnum.rb +162 -0
  23. data/lib/concurrent/atomic/condition.rb +67 -0
  24. data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +118 -0
  25. data/lib/concurrent/atomic/copy_on_write_observer_set.rb +117 -0
  26. data/lib/concurrent/atomic/count_down_latch.rb +116 -0
  27. data/lib/concurrent/atomic/cyclic_barrier.rb +106 -0
  28. data/lib/concurrent/atomic/event.rb +98 -0
  29. data/lib/concurrent/atomic/thread_local_var.rb +117 -0
  30. data/lib/concurrent/atomic_reference/concurrent_update_error.rb +7 -0
  31. data/lib/concurrent/atomic_reference/delegated_update.rb +28 -0
  32. data/lib/concurrent/atomic_reference/direct_update.rb +28 -0
  33. data/lib/concurrent/atomic_reference/jruby.rb +8 -0
  34. data/lib/concurrent/atomic_reference/mutex_atomic.rb +47 -0
  35. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +24 -0
  36. data/lib/concurrent/atomic_reference/rbx.rb +16 -0
  37. data/lib/concurrent/atomic_reference/ruby.rb +16 -0
  38. data/lib/concurrent/atomics.rb +10 -0
  39. data/lib/concurrent/channel/buffered_channel.rb +85 -0
  40. data/lib/concurrent/channel/channel.rb +41 -0
  41. data/lib/concurrent/channel/unbuffered_channel.rb +34 -0
  42. data/lib/concurrent/channel/waitable_list.rb +40 -0
  43. data/lib/concurrent/channels.rb +5 -0
  44. data/lib/concurrent/collection/blocking_ring_buffer.rb +71 -0
  45. data/lib/concurrent/collection/priority_queue.rb +305 -0
  46. data/lib/concurrent/collection/ring_buffer.rb +59 -0
  47. data/lib/concurrent/collections.rb +3 -0
  48. data/lib/concurrent/configuration.rb +158 -0
  49. data/lib/concurrent/dataflow.rb +91 -0
  50. data/lib/concurrent/delay.rb +112 -0
  51. data/lib/concurrent/dereferenceable.rb +101 -0
  52. data/lib/concurrent/errors.rb +30 -0
  53. data/lib/concurrent/exchanger.rb +34 -0
  54. data/lib/concurrent/executor/cached_thread_pool.rb +44 -0
  55. data/lib/concurrent/executor/executor.rb +229 -0
  56. data/lib/concurrent/executor/fixed_thread_pool.rb +33 -0
  57. data/lib/concurrent/executor/immediate_executor.rb +16 -0
  58. data/lib/concurrent/executor/java_cached_thread_pool.rb +31 -0
  59. data/lib/concurrent/executor/java_fixed_thread_pool.rb +33 -0
  60. data/lib/concurrent/executor/java_single_thread_executor.rb +21 -0
  61. data/lib/concurrent/executor/java_thread_pool_executor.rb +187 -0
  62. data/lib/concurrent/executor/per_thread_executor.rb +24 -0
  63. data/lib/concurrent/executor/ruby_cached_thread_pool.rb +29 -0
  64. data/lib/concurrent/executor/ruby_fixed_thread_pool.rb +32 -0
  65. data/lib/concurrent/executor/ruby_single_thread_executor.rb +73 -0
  66. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +286 -0
  67. data/lib/concurrent/executor/ruby_thread_pool_worker.rb +72 -0
  68. data/lib/concurrent/executor/safe_task_executor.rb +35 -0
  69. data/lib/concurrent/executor/serialized_execution.rb +90 -0
  70. data/lib/concurrent/executor/single_thread_executor.rb +35 -0
  71. data/lib/concurrent/executor/thread_pool_executor.rb +68 -0
  72. data/lib/concurrent/executor/timer_set.rb +143 -0
  73. data/lib/concurrent/executors.rb +9 -0
  74. data/lib/concurrent/future.rb +124 -0
  75. data/lib/concurrent/ivar.rb +111 -0
  76. data/lib/concurrent/logging.rb +17 -0
  77. data/lib/concurrent/mvar.rb +200 -0
  78. data/lib/concurrent/obligation.rb +171 -0
  79. data/lib/concurrent/observable.rb +40 -0
  80. data/lib/concurrent/options_parser.rb +46 -0
  81. data/lib/concurrent/promise.rb +169 -0
  82. data/lib/concurrent/scheduled_task.rb +78 -0
  83. data/lib/concurrent/supervisor.rb +343 -0
  84. data/lib/concurrent/timer_task.rb +341 -0
  85. data/lib/concurrent/tvar.rb +252 -0
  86. data/lib/concurrent/utilities.rb +3 -0
  87. data/lib/concurrent/utility/processor_count.rb +150 -0
  88. data/lib/concurrent/utility/timeout.rb +35 -0
  89. data/lib/concurrent/utility/timer.rb +21 -0
  90. data/lib/concurrent/version.rb +3 -0
  91. data/lib/concurrent_ruby.rb +1 -0
  92. data/lib/concurrent_ruby_ext.so +0 -0
  93. data/lib/extension_helper.rb +9 -0
  94. metadata +140 -0
@@ -0,0 +1,169 @@
1
+ require 'thread'
2
+
3
+ require 'concurrent/obligation'
4
+ require 'concurrent/options_parser'
5
+
6
+ module Concurrent
7
+
8
+ class Promise
9
+ include Obligation
10
+
11
+ # Initialize a new Promise with the provided options.
12
+ #
13
+ # @param [Hash] opts the options used to define the behavior at update and deref
14
+ #
15
+ # @option opts [Promise] :parent the parent `Promise` when building a chain/tree
16
+ # @option opts [Proc] :on_fulfill fulfillment handler
17
+ # @option opts [Proc] :on_reject rejection handler
18
+ #
19
+ # @option opts [Boolean] :operation (false) when `true` will execute the future on the global
20
+ # operation pool (for long-running operations), when `false` will execute the future on the
21
+ # global task pool (for short-running tasks)
22
+ # @option opts [object] :executor when provided will run all operations on
23
+ # this executor rather than the global thread pool (overrides :operation)
24
+ #
25
+ # @option opts [String] :dup_on_deref (false) call `#dup` before returning the data
26
+ # @option opts [String] :freeze_on_deref (false) call `#freeze` before returning the data
27
+ # @option opts [String] :copy_on_deref (nil) call the given `Proc` passing the internal value and
28
+ # returning the value returned from the proc
29
+ #
30
+ # @see http://wiki.commonjs.org/wiki/Promises/A
31
+ # @see http://promises-aplus.github.io/promises-spec/
32
+ def initialize(opts = {}, &block)
33
+ opts.delete_if { |k, v| v.nil? }
34
+
35
+ @executor = OptionsParser::get_executor_from(opts)
36
+ @parent = opts.fetch(:parent) { nil }
37
+ @on_fulfill = opts.fetch(:on_fulfill) { Proc.new { |result| result } }
38
+ @on_reject = opts.fetch(:on_reject) { Proc.new { |reason| raise reason } }
39
+
40
+ @promise_body = block || Proc.new { |result| result }
41
+ @state = :unscheduled
42
+ @children = []
43
+
44
+ init_obligation
45
+ end
46
+
47
+ # @return [Promise]
48
+ def self.fulfill(value, opts = {})
49
+ Promise.new(opts).tap { |p| p.send(:synchronized_set_state!, true, value, nil) }
50
+ end
51
+
52
+
53
+ # @return [Promise]
54
+ def self.reject(reason, opts = {})
55
+ Promise.new(opts).tap { |p| p.send(:synchronized_set_state!, false, nil, reason) }
56
+ end
57
+
58
+ # @return [Promise]
59
+ # @since 0.5.0
60
+ def execute
61
+ if root?
62
+ if compare_and_set_state(:pending, :unscheduled)
63
+ set_pending
64
+ realize(@promise_body)
65
+ end
66
+ else
67
+ @parent.execute
68
+ end
69
+ self
70
+ end
71
+
72
+ # @since 0.5.0
73
+ def self.execute(opts = {}, &block)
74
+ new(opts, &block).execute
75
+ end
76
+
77
+ # @return [Promise] the new promise
78
+ def then(rescuer = nil, &block)
79
+ raise ArgumentError.new('rescuers and block are both missing') if rescuer.nil? && !block_given?
80
+ block = Proc.new { |result| result } if block.nil?
81
+ child = Promise.new(
82
+ parent: self,
83
+ executor: @executor,
84
+ on_fulfill: block,
85
+ on_reject: rescuer
86
+ )
87
+
88
+ mutex.synchronize do
89
+ child.state = :pending if @state == :pending
90
+ child.on_fulfill(apply_deref_options(@value)) if @state == :fulfilled
91
+ child.on_reject(@reason) if @state == :rejected
92
+ @children << child
93
+ end
94
+
95
+ child
96
+ end
97
+
98
+ # @return [Promise]
99
+ def on_success(&block)
100
+ raise ArgumentError.new('no block given') unless block_given?
101
+ self.then &block
102
+ end
103
+
104
+ # @return [Promise]
105
+ def rescue(&block)
106
+ self.then(block)
107
+ end
108
+
109
+ alias_method :catch, :rescue
110
+ alias_method :on_error, :rescue
111
+
112
+ protected
113
+
114
+ def set_pending
115
+ mutex.synchronize do
116
+ @state = :pending
117
+ @children.each { |c| c.set_pending }
118
+ end
119
+ end
120
+
121
+ # @!visibility private
122
+ def root? # :nodoc:
123
+ @parent.nil?
124
+ end
125
+
126
+ # @!visibility private
127
+ def on_fulfill(result)
128
+ realize Proc.new { @on_fulfill.call(result) }
129
+ nil
130
+ end
131
+
132
+ # @!visibility private
133
+ def on_reject(reason)
134
+ realize Proc.new { @on_reject.call(reason) }
135
+ nil
136
+ end
137
+
138
+ def notify_child(child)
139
+ if_state(:fulfilled) { child.on_fulfill(apply_deref_options(@value)) }
140
+ if_state(:rejected) { child.on_reject(@reason) }
141
+ end
142
+
143
+ # @!visibility private
144
+ def realize(task)
145
+ @executor.post do
146
+ success, value, reason = SafeTaskExecutor.new(task).execute
147
+
148
+ children_to_notify = mutex.synchronize do
149
+ set_state!(success, value, reason)
150
+ @children.dup
151
+ end
152
+
153
+ children_to_notify.each { |child| notify_child(child) }
154
+ end
155
+ end
156
+
157
+ def set_state!(success, value, reason)
158
+ set_state(success, value, reason)
159
+ event.set
160
+ end
161
+
162
+ def synchronized_set_state!(success, value, reason)
163
+ mutex.lock
164
+ set_state!(success, value, reason)
165
+ ensure
166
+ mutex.unlock
167
+ end
168
+ end
169
+ end
@@ -0,0 +1,78 @@
1
+ require 'concurrent/ivar'
2
+ require 'concurrent/utility/timer'
3
+ require 'concurrent/executor/safe_task_executor'
4
+
5
+ module Concurrent
6
+
7
+ class ScheduledTask < IVar
8
+
9
+ attr_reader :schedule_time
10
+
11
+ def initialize(intended_time, opts = {}, &block)
12
+ raise ArgumentError.new('no block given') unless block_given?
13
+ TimerSet.calculate_schedule_time(intended_time) # raises exceptons
14
+
15
+ super(NO_VALUE, opts)
16
+
17
+ self.observers = CopyOnNotifyObserverSet.new
18
+ @intended_time = intended_time
19
+ @state = :unscheduled
20
+ @task = block
21
+ end
22
+
23
+ # @since 0.5.0
24
+ def execute
25
+ if compare_and_set_state(:pending, :unscheduled)
26
+ @schedule_time = TimerSet.calculate_schedule_time(@intended_time)
27
+ Concurrent::timer(@schedule_time.to_f - Time.now.to_f, &method(:process_task))
28
+ self
29
+ end
30
+ end
31
+
32
+ # @since 0.5.0
33
+ def self.execute(intended_time, opts = {}, &block)
34
+ return ScheduledTask.new(intended_time, opts, &block).execute
35
+ end
36
+
37
+ def cancelled?
38
+ state == :cancelled
39
+ end
40
+
41
+ def in_progress?
42
+ state == :in_progress
43
+ end
44
+
45
+ def cancel
46
+ if_state(:unscheduled, :pending) do
47
+ @state = :cancelled
48
+ event.set
49
+ true
50
+ end
51
+ end
52
+ alias_method :stop, :cancel
53
+
54
+ def add_observer(*args, &block)
55
+ if_state(:unscheduled, :pending, :in_progress) do
56
+ observers.add_observer(*args, &block)
57
+ end
58
+ end
59
+
60
+ protected :set, :fail, :complete
61
+
62
+ private
63
+
64
+ def process_task
65
+ if compare_and_set_state(:in_progress, :pending)
66
+ success, val, reason = SafeTaskExecutor.new(@task).execute
67
+
68
+ mutex.synchronize do
69
+ set_state(success, val, reason)
70
+ event.set
71
+ end
72
+
73
+ time = Time.now
74
+ observers.notify_and_delete_observers{ [time, self.value, reason] }
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,343 @@
1
+ require 'thread'
2
+
3
+ require 'concurrent/errors'
4
+
5
+ module Concurrent
6
+
7
+ class Supervisor
8
+
9
+ DEFAULT_MONITOR_INTERVAL = 1
10
+ RESTART_STRATEGIES = [:one_for_one, :one_for_all, :rest_for_one]
11
+ DEFAULT_MAX_RESTART = 5
12
+ DEFAULT_MAX_TIME = 60
13
+ WORKER_API = {run: 0, stop: 0, running?: 0}
14
+
15
+ CHILD_TYPES = [:worker, :supervisor]
16
+ CHILD_RESTART_OPTIONS = [:permanent, :transient, :temporary]
17
+
18
+ WorkerContext = Struct.new(:worker, :type, :restart) do
19
+ attr_accessor :thread
20
+ attr_accessor :terminated
21
+
22
+ def alive?() return thread && thread.alive?; end
23
+
24
+ def needs_restart?
25
+ return false if thread && thread.alive?
26
+ return false if terminated
27
+ case self.restart
28
+ when :permanent
29
+ return true
30
+ when :transient
31
+ return thread.nil? || thread.status.nil?
32
+ else #when :temporary
33
+ return false
34
+ end
35
+ end
36
+ end
37
+
38
+ WorkerCounts = Struct.new(:specs, :supervisors, :workers) do
39
+ attr_accessor :status
40
+ def add(context)
41
+ self.specs += 1
42
+ self.supervisors += 1 if context.type == :supervisor
43
+ self.workers += 1 if context.type == :worker
44
+ end
45
+ def active() sleeping + running + aborting end
46
+ def sleeping() @status.reduce(0){|x, s| x += (s == 'sleep' ? 1 : 0) } end
47
+ def running() @status.reduce(0){|x, s| x += (s == 'run' ? 1 : 0) } end
48
+ def aborting() @status.reduce(0){|x, s| x += (s == 'aborting' ? 1 : 0) } end
49
+ def stopped() @status.reduce(0){|x, s| x += (s == false ? 1 : 0) } end
50
+ def abend() @status.reduce(0){|x, s| x += (s.nil? ? 1 : 0) } end
51
+ end
52
+
53
+ attr_reader :monitor_interval
54
+ attr_reader :restart_strategy
55
+ attr_reader :max_restart
56
+ attr_reader :max_time
57
+
58
+ alias_method :strategy, :restart_strategy
59
+ alias_method :max_r, :max_restart
60
+ alias_method :max_t, :max_time
61
+
62
+ def initialize(opts = {})
63
+ warn '[EXPERIMENTAL] Supervisor is being completely rewritten and will change soon.'
64
+ @restart_strategy = opts[:restart_strategy] || opts[:strategy] || :one_for_one
65
+ @monitor_interval = (opts[:monitor_interval] || DEFAULT_MONITOR_INTERVAL).to_f
66
+ @max_restart = (opts[:max_restart] || opts[:max_r] || DEFAULT_MAX_RESTART).to_i
67
+ @max_time = (opts[:max_time] || opts[:max_t] || DEFAULT_MAX_TIME).to_i
68
+
69
+ raise ArgumentError.new(":#{@restart_strategy} is not a valid restart strategy") unless RESTART_STRATEGIES.include?(@restart_strategy)
70
+ raise ArgumentError.new(':monitor_interval must be greater than zero') unless @monitor_interval > 0.0
71
+ raise ArgumentError.new(':max_restart must be greater than zero') unless @max_restart > 0
72
+ raise ArgumentError.new(':max_time must be greater than zero') unless @max_time > 0
73
+
74
+ @running = false
75
+ @mutex = Mutex.new
76
+ @workers = []
77
+ @monitor = nil
78
+
79
+ @count = WorkerCounts.new(0, 0, 0)
80
+ @restart_times = []
81
+
82
+ add_worker(opts[:worker]) unless opts[:worker].nil?
83
+ add_workers(opts[:workers]) unless opts[:workers].nil?
84
+ end
85
+
86
+ def run!
87
+ @mutex.synchronize do
88
+ raise StandardError.new('already running') if @running
89
+ @running = true
90
+ @monitor = Thread.new do
91
+ Thread.current.abort_on_exception = false
92
+ monitor
93
+ end
94
+ end
95
+ Thread.pass
96
+ end
97
+
98
+ def run
99
+ @mutex.synchronize do
100
+ raise StandardError.new('already running') if @running
101
+ @running = true
102
+ end
103
+ monitor
104
+ true
105
+ end
106
+
107
+ def stop
108
+ @mutex.synchronize do
109
+ return true unless @running
110
+
111
+ @running = false
112
+ unless @monitor.nil?
113
+ @monitor.run if @monitor.status == 'sleep'
114
+ if @monitor.join(0.1).nil?
115
+ @monitor.kill
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)
124
+ end
125
+ prune_workers
126
+ end
127
+
128
+ true
129
+ end
130
+
131
+ def running?
132
+ @mutex.synchronize { @running }
133
+ end
134
+
135
+ def length
136
+ @mutex.synchronize { @workers.length }
137
+ end
138
+ alias_method :size, :length
139
+
140
+ def current_restart_count
141
+ @restart_times.length
142
+ end
143
+
144
+ def count
145
+ @mutex.synchronize do
146
+ @count.status = @workers.collect{|w| w.thread ? w.thread.status : false }
147
+ @count.dup.freeze
148
+ end
149
+ end
150
+
151
+ def add_worker(worker, opts = {})
152
+ return nil if worker.nil? || ! behaves_as_worker?(worker)
153
+ @mutex.synchronize {
154
+ restart = opts[:restart] || :permanent
155
+ type = opts[:type] || (worker.is_a?(Supervisor) ? :supervisor : nil) || :worker
156
+ raise ArgumentError.new(":#{restart} is not a valid restart option") unless CHILD_RESTART_OPTIONS.include?(restart)
157
+ raise ArgumentError.new(":#{type} is not a valid child type") unless CHILD_TYPES.include?(type)
158
+ context = WorkerContext.new(worker, type, restart)
159
+ @workers << context
160
+ @count.add(context)
161
+ worker.run if @running
162
+ context.object_id
163
+ }
164
+ end
165
+ alias_method :add_child, :add_worker
166
+
167
+ def add_workers(workers, opts = {})
168
+ workers.collect do |worker|
169
+ add_worker(worker, opts)
170
+ end
171
+ end
172
+ alias_method :add_children, :add_workers
173
+
174
+ def remove_worker(worker_id)
175
+ @mutex.synchronize do
176
+ index, context = find_worker(worker_id)
177
+ break(nil) if context.nil?
178
+ break(false) if context.alive?
179
+ @workers.delete_at(index)
180
+ context.worker
181
+ end
182
+ end
183
+ alias_method :remove_child, :remove_worker
184
+
185
+ def stop_worker(worker_id)
186
+ @mutex.synchronize do
187
+ return true unless @running
188
+
189
+ index, context = find_worker(worker_id)
190
+ break(nil) if index.nil?
191
+ context.terminated = true
192
+ terminate_worker(context)
193
+ @workers.delete_at(index) if @workers[index].restart == :temporary
194
+ true
195
+ end
196
+ end
197
+ alias_method :stop_child, :stop_worker
198
+
199
+ def start_worker(worker_id)
200
+ @mutex.synchronize do
201
+ return false unless @running
202
+
203
+ index, context = find_worker(worker_id)
204
+ break(nil) if context.nil?
205
+ context.terminated = false
206
+ run_worker(context) unless context.alive?
207
+ true
208
+ end
209
+ end
210
+ alias_method :start_child, :start_worker
211
+
212
+ def restart_worker(worker_id)
213
+ @mutex.synchronize do
214
+ return false unless @running
215
+
216
+ index, context = find_worker(worker_id)
217
+ break(nil) if context.nil?
218
+ break(false) if context.restart == :temporary
219
+ context.terminated = false
220
+ terminate_worker(context)
221
+ run_worker(context)
222
+ true
223
+ end
224
+ end
225
+ alias_method :restart_child, :restart_worker
226
+
227
+ private
228
+
229
+ def behaves_as_worker?(obj)
230
+ WORKER_API.each do |method, arity|
231
+ break(false) unless obj.respond_to?(method) && obj.method(method).arity == arity
232
+ true
233
+ end
234
+ end
235
+
236
+ def monitor
237
+ @workers.each{|context| run_worker(context)}
238
+ loop do
239
+ sleep(@monitor_interval)
240
+ break unless running?
241
+ @mutex.synchronize do
242
+ prune_workers
243
+ self.send(@restart_strategy)
244
+ end
245
+ break unless running?
246
+ end
247
+ rescue MaxRestartFrequencyError => ex
248
+ stop
249
+ end
250
+
251
+ def run_worker(context)
252
+ context.thread = Thread.new do
253
+ Thread.current.abort_on_exception = false
254
+ context.worker.run
255
+ end
256
+ context
257
+ end
258
+
259
+ def terminate_worker(context)
260
+ if context.alive?
261
+ context.worker.stop
262
+ Thread.pass
263
+ end
264
+ rescue Exception => ex
265
+ begin
266
+ Thread.kill(context.thread)
267
+ rescue
268
+ # suppress
269
+ end
270
+ ensure
271
+ context.thread = nil
272
+ end
273
+
274
+ def prune_workers
275
+ @workers.delete_if{|w| w.restart == :temporary && ! w.alive? }
276
+ end
277
+
278
+ def find_worker(worker_id)
279
+ index = @workers.find_index{|worker| worker.object_id == worker_id}
280
+ if index.nil?
281
+ [nil, nil]
282
+ else
283
+ [index, @workers[index]]
284
+ end
285
+ end
286
+
287
+ def exceeded_max_restart_frequency?
288
+ @restart_times.unshift(Time.now.to_i)
289
+ diff = (@restart_times.first - @restart_times.last).abs
290
+ if @restart_times.length >= @max_restart && diff <= @max_time
291
+ return true
292
+ elsif diff >= @max_time
293
+ @restart_times.pop
294
+ end
295
+ false
296
+ end
297
+
298
+ #----------------------------------------------------------------
299
+ # restart strategies
300
+
301
+ def one_for_one
302
+ @workers.each do |context|
303
+ if context.needs_restart?
304
+ raise MaxRestartFrequencyError if exceeded_max_restart_frequency?
305
+ run_worker(context)
306
+ end
307
+ end
308
+ end
309
+
310
+ def one_for_all
311
+ restart = false
312
+
313
+ restart = @workers.each do |context|
314
+ if context.needs_restart?
315
+ raise MaxRestartFrequencyError if exceeded_max_restart_frequency?
316
+ break(true)
317
+ end
318
+ end
319
+
320
+ if restart
321
+ @workers.each do |context|
322
+ terminate_worker(context)
323
+ end
324
+ @workers.each{|context| run_worker(context)}
325
+ end
326
+ end
327
+
328
+ def rest_for_one
329
+ restart = false
330
+
331
+ @workers.each do |context|
332
+ if restart
333
+ terminate_worker(context)
334
+ elsif context.needs_restart?
335
+ raise MaxRestartFrequencyError if exceeded_max_restart_frequency?
336
+ restart = true
337
+ end
338
+ end
339
+
340
+ one_for_one if restart
341
+ end
342
+ end
343
+ end