concurrent-ruby 0.7.0.rc0-x64-mingw32

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.
Files changed (95) 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/2.0/concurrent_ruby_ext.so +0 -0
  9. data/lib/concurrent.rb +45 -0
  10. data/lib/concurrent/actress.rb +221 -0
  11. data/lib/concurrent/actress/ad_hoc.rb +20 -0
  12. data/lib/concurrent/actress/context.rb +98 -0
  13. data/lib/concurrent/actress/core.rb +228 -0
  14. data/lib/concurrent/actress/core_delegations.rb +42 -0
  15. data/lib/concurrent/actress/envelope.rb +41 -0
  16. data/lib/concurrent/actress/errors.rb +14 -0
  17. data/lib/concurrent/actress/reference.rb +64 -0
  18. data/lib/concurrent/actress/type_check.rb +48 -0
  19. data/lib/concurrent/agent.rb +232 -0
  20. data/lib/concurrent/async.rb +319 -0
  21. data/lib/concurrent/atomic.rb +46 -0
  22. data/lib/concurrent/atomic/atomic_boolean.rb +157 -0
  23. data/lib/concurrent/atomic/atomic_fixnum.rb +162 -0
  24. data/lib/concurrent/atomic/condition.rb +67 -0
  25. data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +118 -0
  26. data/lib/concurrent/atomic/copy_on_write_observer_set.rb +117 -0
  27. data/lib/concurrent/atomic/count_down_latch.rb +116 -0
  28. data/lib/concurrent/atomic/cyclic_barrier.rb +106 -0
  29. data/lib/concurrent/atomic/event.rb +98 -0
  30. data/lib/concurrent/atomic/thread_local_var.rb +117 -0
  31. data/lib/concurrent/atomic_reference/concurrent_update_error.rb +7 -0
  32. data/lib/concurrent/atomic_reference/delegated_update.rb +28 -0
  33. data/lib/concurrent/atomic_reference/direct_update.rb +28 -0
  34. data/lib/concurrent/atomic_reference/jruby.rb +8 -0
  35. data/lib/concurrent/atomic_reference/mutex_atomic.rb +47 -0
  36. data/lib/concurrent/atomic_reference/numeric_cas_wrapper.rb +24 -0
  37. data/lib/concurrent/atomic_reference/rbx.rb +16 -0
  38. data/lib/concurrent/atomic_reference/ruby.rb +16 -0
  39. data/lib/concurrent/atomics.rb +10 -0
  40. data/lib/concurrent/channel/buffered_channel.rb +85 -0
  41. data/lib/concurrent/channel/channel.rb +41 -0
  42. data/lib/concurrent/channel/unbuffered_channel.rb +34 -0
  43. data/lib/concurrent/channel/waitable_list.rb +40 -0
  44. data/lib/concurrent/channels.rb +5 -0
  45. data/lib/concurrent/collection/blocking_ring_buffer.rb +71 -0
  46. data/lib/concurrent/collection/priority_queue.rb +305 -0
  47. data/lib/concurrent/collection/ring_buffer.rb +59 -0
  48. data/lib/concurrent/collections.rb +3 -0
  49. data/lib/concurrent/configuration.rb +158 -0
  50. data/lib/concurrent/dataflow.rb +91 -0
  51. data/lib/concurrent/delay.rb +112 -0
  52. data/lib/concurrent/dereferenceable.rb +101 -0
  53. data/lib/concurrent/errors.rb +30 -0
  54. data/lib/concurrent/exchanger.rb +34 -0
  55. data/lib/concurrent/executor/cached_thread_pool.rb +44 -0
  56. data/lib/concurrent/executor/executor.rb +229 -0
  57. data/lib/concurrent/executor/fixed_thread_pool.rb +33 -0
  58. data/lib/concurrent/executor/immediate_executor.rb +16 -0
  59. data/lib/concurrent/executor/java_cached_thread_pool.rb +31 -0
  60. data/lib/concurrent/executor/java_fixed_thread_pool.rb +33 -0
  61. data/lib/concurrent/executor/java_single_thread_executor.rb +21 -0
  62. data/lib/concurrent/executor/java_thread_pool_executor.rb +187 -0
  63. data/lib/concurrent/executor/per_thread_executor.rb +24 -0
  64. data/lib/concurrent/executor/ruby_cached_thread_pool.rb +29 -0
  65. data/lib/concurrent/executor/ruby_fixed_thread_pool.rb +32 -0
  66. data/lib/concurrent/executor/ruby_single_thread_executor.rb +73 -0
  67. data/lib/concurrent/executor/ruby_thread_pool_executor.rb +286 -0
  68. data/lib/concurrent/executor/ruby_thread_pool_worker.rb +72 -0
  69. data/lib/concurrent/executor/safe_task_executor.rb +35 -0
  70. data/lib/concurrent/executor/serialized_execution.rb +90 -0
  71. data/lib/concurrent/executor/single_thread_executor.rb +35 -0
  72. data/lib/concurrent/executor/thread_pool_executor.rb +68 -0
  73. data/lib/concurrent/executor/timer_set.rb +143 -0
  74. data/lib/concurrent/executors.rb +9 -0
  75. data/lib/concurrent/future.rb +124 -0
  76. data/lib/concurrent/ivar.rb +111 -0
  77. data/lib/concurrent/logging.rb +17 -0
  78. data/lib/concurrent/mvar.rb +200 -0
  79. data/lib/concurrent/obligation.rb +171 -0
  80. data/lib/concurrent/observable.rb +40 -0
  81. data/lib/concurrent/options_parser.rb +46 -0
  82. data/lib/concurrent/promise.rb +169 -0
  83. data/lib/concurrent/scheduled_task.rb +78 -0
  84. data/lib/concurrent/supervisor.rb +343 -0
  85. data/lib/concurrent/timer_task.rb +341 -0
  86. data/lib/concurrent/tvar.rb +252 -0
  87. data/lib/concurrent/utilities.rb +3 -0
  88. data/lib/concurrent/utility/processor_count.rb +150 -0
  89. data/lib/concurrent/utility/timeout.rb +35 -0
  90. data/lib/concurrent/utility/timer.rb +21 -0
  91. data/lib/concurrent/version.rb +3 -0
  92. data/lib/concurrent_ruby.rb +1 -0
  93. data/lib/concurrent_ruby_ext.so +0 -0
  94. data/lib/extension_helper.rb +9 -0
  95. metadata +141 -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