concurrent-ruby 0.6.0.pre.2 → 0.6.0
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 +3 -8
- data/lib/concurrent.rb +2 -0
- data/lib/concurrent/actor/actor.rb +3 -3
- data/lib/concurrent/actor/postable.rb +1 -1
- data/lib/concurrent/actors.rb +0 -3
- data/lib/concurrent/actress.rb +75 -0
- data/lib/concurrent/actress/ad_hoc.rb +14 -0
- data/lib/concurrent/actress/context.rb +96 -0
- data/lib/concurrent/actress/core.rb +204 -0
- data/lib/concurrent/actress/core_delegations.rb +37 -0
- data/lib/concurrent/actress/doc.md +53 -0
- data/lib/concurrent/actress/envelope.rb +25 -0
- data/lib/concurrent/actress/errors.rb +14 -0
- data/lib/concurrent/actress/reference.rb +64 -0
- data/lib/concurrent/actress/type_check.rb +48 -0
- data/lib/concurrent/agent.rb +20 -11
- data/lib/concurrent/async.rb +54 -25
- data/lib/concurrent/atomic/atomic.rb +48 -0
- data/lib/concurrent/atomic/atomic_boolean.rb +13 -13
- data/lib/concurrent/atomic/atomic_fixnum.rb +9 -17
- data/lib/concurrent/atomic/copy_on_notify_observer_set.rb +7 -4
- data/lib/concurrent/atomic/copy_on_write_observer_set.rb +16 -14
- data/lib/concurrent/atomic/event.rb +11 -16
- data/lib/concurrent/atomics.rb +1 -0
- data/lib/concurrent/channel/channel.rb +4 -2
- data/lib/concurrent/collection/blocking_ring_buffer.rb +1 -1
- data/lib/concurrent/configuration.rb +59 -47
- data/lib/concurrent/delay.rb +28 -12
- data/lib/concurrent/dereferenceable.rb +6 -6
- data/lib/concurrent/errors.rb +30 -0
- data/lib/concurrent/executor/executor.rb +11 -4
- data/lib/concurrent/executor/immediate_executor.rb +1 -0
- data/lib/concurrent/executor/java_thread_pool_executor.rb +4 -0
- data/lib/concurrent/executor/one_by_one.rb +24 -12
- data/lib/concurrent/executor/per_thread_executor.rb +1 -0
- data/lib/concurrent/executor/ruby_single_thread_executor.rb +2 -1
- data/lib/concurrent/executor/ruby_thread_pool_executor.rb +7 -2
- data/lib/concurrent/executor/ruby_thread_pool_worker.rb +3 -0
- data/lib/concurrent/executor/timer_set.rb +1 -1
- data/lib/concurrent/future.rb +0 -2
- data/lib/concurrent/ivar.rb +31 -6
- data/lib/concurrent/logging.rb +17 -0
- data/lib/concurrent/mvar.rb +45 -0
- data/lib/concurrent/obligation.rb +61 -20
- data/lib/concurrent/observable.rb +7 -0
- data/lib/concurrent/promise.rb +1 -0
- data/lib/concurrent/runnable.rb +2 -2
- data/lib/concurrent/supervisor.rb +1 -2
- data/lib/concurrent/timer_task.rb +17 -13
- data/lib/concurrent/tvar.rb +113 -73
- data/lib/concurrent/utility/processor_count.rb +141 -116
- data/lib/concurrent/utility/timeout.rb +4 -5
- data/lib/concurrent/version.rb +1 -1
- data/spec/concurrent/actor/postable_shared.rb +1 -1
- data/spec/concurrent/actress_spec.rb +191 -0
- data/spec/concurrent/async_spec.rb +35 -3
- data/spec/concurrent/atomic/atomic_boolean_spec.rb +1 -1
- data/spec/concurrent/atomic/atomic_fixnum_spec.rb +1 -1
- data/spec/concurrent/atomic/atomic_spec.rb +133 -0
- data/spec/concurrent/atomic/count_down_latch_spec.rb +1 -1
- data/spec/concurrent/collection/priority_queue_spec.rb +1 -1
- data/spec/concurrent/configuration_spec.rb +5 -2
- data/spec/concurrent/delay_spec.rb +14 -0
- data/spec/concurrent/exchanger_spec.rb +4 -9
- data/spec/concurrent/executor/java_cached_thread_pool_spec.rb +1 -1
- data/spec/concurrent/executor/java_fixed_thread_pool_spec.rb +1 -1
- data/spec/concurrent/executor/java_single_thread_executor_spec.rb +1 -1
- data/spec/concurrent/executor/java_thread_pool_executor_spec.rb +1 -1
- data/spec/concurrent/executor/ruby_thread_pool_executor_spec.rb +4 -4
- data/spec/concurrent/ivar_spec.rb +2 -2
- data/spec/concurrent/obligation_spec.rb +113 -24
- data/spec/concurrent/observable_shared.rb +4 -0
- data/spec/concurrent/observable_spec.rb +8 -3
- data/spec/concurrent/runnable_spec.rb +2 -2
- data/spec/concurrent/scheduled_task_spec.rb +1 -0
- data/spec/concurrent/supervisor_spec.rb +26 -11
- data/spec/concurrent/timer_task_spec.rb +36 -35
- data/spec/concurrent/tvar_spec.rb +1 -1
- data/spec/concurrent/utility/timer_spec.rb +8 -8
- data/spec/spec_helper.rb +8 -18
- data/spec/support/example_group_extensions.rb +48 -0
- metadata +23 -16
- data/lib/concurrent/actor/actor_context.rb +0 -77
- data/lib/concurrent/actor/actor_ref.rb +0 -67
- data/lib/concurrent/actor/simple_actor_ref.rb +0 -94
- data/lib/concurrent_ruby_ext.bundle +0 -0
- data/spec/concurrent/actor/actor_context_spec.rb +0 -29
- data/spec/concurrent/actor/actor_ref_shared.rb +0 -263
- data/spec/concurrent/actor/simple_actor_ref_spec.rb +0 -135
- data/spec/support/functions.rb +0 -25
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
|
3
|
+
module Concurrent
|
4
|
+
module TestHelpers
|
5
|
+
def delta(v1, v2)
|
6
|
+
if block_given?
|
7
|
+
v1 = yield(v1)
|
8
|
+
v2 = yield(v2)
|
9
|
+
end
|
10
|
+
return (v1 - v2).abs
|
11
|
+
end
|
12
|
+
|
13
|
+
def mri?
|
14
|
+
RbConfig::CONFIG['ruby_install_name']=~ /^ruby$/i
|
15
|
+
end
|
16
|
+
|
17
|
+
def jruby?
|
18
|
+
RbConfig::CONFIG['ruby_install_name']=~ /^jruby$/i
|
19
|
+
end
|
20
|
+
|
21
|
+
def rbx?
|
22
|
+
RbConfig::CONFIG['ruby_install_name']=~ /^rbx$/i
|
23
|
+
end
|
24
|
+
|
25
|
+
def reset_gem_configuration
|
26
|
+
Concurrent.instance_variable_set(:@configuration, Concurrent::Configuration.new)
|
27
|
+
end
|
28
|
+
|
29
|
+
extend self
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class RSpec::Core::ExampleGroup
|
34
|
+
def self.with_full_reset
|
35
|
+
before(:each) do
|
36
|
+
reset_gem_configuration
|
37
|
+
end
|
38
|
+
|
39
|
+
after(:each) do
|
40
|
+
Thread.list.each do |thread|
|
41
|
+
thread.kill unless thread == Thread.current
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
include Concurrent::TestHelpers
|
47
|
+
extend Concurrent::TestHelpers
|
48
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: concurrent-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.0
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jerry D'Antonio
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-05-
|
11
|
+
date: 2014-05-26 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: |2
|
14
14
|
Modern concurrency tools including agents, futures, promises, thread pools, actors, supervisors, and more.
|
@@ -24,13 +24,21 @@ files:
|
|
24
24
|
- README.md
|
25
25
|
- lib/concurrent.rb
|
26
26
|
- lib/concurrent/actor/actor.rb
|
27
|
-
- lib/concurrent/actor/actor_context.rb
|
28
|
-
- lib/concurrent/actor/actor_ref.rb
|
29
27
|
- lib/concurrent/actor/postable.rb
|
30
|
-
- lib/concurrent/actor/simple_actor_ref.rb
|
31
28
|
- lib/concurrent/actors.rb
|
29
|
+
- lib/concurrent/actress.rb
|
30
|
+
- lib/concurrent/actress/ad_hoc.rb
|
31
|
+
- lib/concurrent/actress/context.rb
|
32
|
+
- lib/concurrent/actress/core.rb
|
33
|
+
- lib/concurrent/actress/core_delegations.rb
|
34
|
+
- lib/concurrent/actress/doc.md
|
35
|
+
- lib/concurrent/actress/envelope.rb
|
36
|
+
- lib/concurrent/actress/errors.rb
|
37
|
+
- lib/concurrent/actress/reference.rb
|
38
|
+
- lib/concurrent/actress/type_check.rb
|
32
39
|
- lib/concurrent/agent.rb
|
33
40
|
- lib/concurrent/async.rb
|
41
|
+
- lib/concurrent/atomic/atomic.rb
|
34
42
|
- lib/concurrent/atomic/atomic_boolean.rb
|
35
43
|
- lib/concurrent/atomic/atomic_fixnum.rb
|
36
44
|
- lib/concurrent/atomic/condition.rb
|
@@ -54,6 +62,7 @@ files:
|
|
54
62
|
- lib/concurrent/dataflow.rb
|
55
63
|
- lib/concurrent/delay.rb
|
56
64
|
- lib/concurrent/dereferenceable.rb
|
65
|
+
- lib/concurrent/errors.rb
|
57
66
|
- lib/concurrent/exchanger.rb
|
58
67
|
- lib/concurrent/executor/cached_thread_pool.rb
|
59
68
|
- lib/concurrent/executor/executor.rb
|
@@ -77,6 +86,7 @@ files:
|
|
77
86
|
- lib/concurrent/executors.rb
|
78
87
|
- lib/concurrent/future.rb
|
79
88
|
- lib/concurrent/ivar.rb
|
89
|
+
- lib/concurrent/logging.rb
|
80
90
|
- lib/concurrent/mvar.rb
|
81
91
|
- lib/concurrent/obligation.rb
|
82
92
|
- lib/concurrent/observable.rb
|
@@ -94,16 +104,14 @@ files:
|
|
94
104
|
- lib/concurrent/utility/timer.rb
|
95
105
|
- lib/concurrent/version.rb
|
96
106
|
- lib/concurrent_ruby.rb
|
97
|
-
- lib/concurrent_ruby_ext.bundle
|
98
|
-
- spec/concurrent/actor/actor_context_spec.rb
|
99
|
-
- spec/concurrent/actor/actor_ref_shared.rb
|
100
107
|
- spec/concurrent/actor/actor_spec.rb
|
101
108
|
- spec/concurrent/actor/postable_shared.rb
|
102
|
-
- spec/concurrent/
|
109
|
+
- spec/concurrent/actress_spec.rb
|
103
110
|
- spec/concurrent/agent_spec.rb
|
104
111
|
- spec/concurrent/async_spec.rb
|
105
112
|
- spec/concurrent/atomic/atomic_boolean_spec.rb
|
106
113
|
- spec/concurrent/atomic/atomic_fixnum_spec.rb
|
114
|
+
- spec/concurrent/atomic/atomic_spec.rb
|
107
115
|
- spec/concurrent/atomic/condition_spec.rb
|
108
116
|
- spec/concurrent/atomic/copy_on_notify_observer_set_spec.rb
|
109
117
|
- spec/concurrent/atomic/copy_on_write_observer_set_spec.rb
|
@@ -162,7 +170,7 @@ files:
|
|
162
170
|
- spec/concurrent/utility/timeout_spec.rb
|
163
171
|
- spec/concurrent/utility/timer_spec.rb
|
164
172
|
- spec/spec_helper.rb
|
165
|
-
- spec/support/
|
173
|
+
- spec/support/example_group_extensions.rb
|
166
174
|
- spec/support/less_than_or_equal_to_matcher.rb
|
167
175
|
homepage: http://www.concurrent-ruby.com
|
168
176
|
licenses:
|
@@ -179,9 +187,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
179
187
|
version: 1.9.3
|
180
188
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
181
189
|
requirements:
|
182
|
-
- - "
|
190
|
+
- - ">="
|
183
191
|
- !ruby/object:Gem::Version
|
184
|
-
version:
|
192
|
+
version: '0'
|
185
193
|
requirements: []
|
186
194
|
rubyforge_project:
|
187
195
|
rubygems_version: 2.2.2
|
@@ -190,15 +198,14 @@ specification_version: 4
|
|
190
198
|
summary: Modern concurrency tools for Ruby. Inspired by Erlang, Clojure, Scala, Haskell,
|
191
199
|
F#, C#, Java, and classic concurrency patterns.
|
192
200
|
test_files:
|
193
|
-
- spec/concurrent/actor/actor_context_spec.rb
|
194
|
-
- spec/concurrent/actor/actor_ref_shared.rb
|
195
201
|
- spec/concurrent/actor/actor_spec.rb
|
196
202
|
- spec/concurrent/actor/postable_shared.rb
|
197
|
-
- spec/concurrent/
|
203
|
+
- spec/concurrent/actress_spec.rb
|
198
204
|
- spec/concurrent/agent_spec.rb
|
199
205
|
- spec/concurrent/async_spec.rb
|
200
206
|
- spec/concurrent/atomic/atomic_boolean_spec.rb
|
201
207
|
- spec/concurrent/atomic/atomic_fixnum_spec.rb
|
208
|
+
- spec/concurrent/atomic/atomic_spec.rb
|
202
209
|
- spec/concurrent/atomic/condition_spec.rb
|
203
210
|
- spec/concurrent/atomic/copy_on_notify_observer_set_spec.rb
|
204
211
|
- spec/concurrent/atomic/copy_on_write_observer_set_spec.rb
|
@@ -257,6 +264,6 @@ test_files:
|
|
257
264
|
- spec/concurrent/utility/timeout_spec.rb
|
258
265
|
- spec/concurrent/utility/timer_spec.rb
|
259
266
|
- spec/spec_helper.rb
|
260
|
-
- spec/support/
|
267
|
+
- spec/support/example_group_extensions.rb
|
261
268
|
- spec/support/less_than_or_equal_to_matcher.rb
|
262
269
|
has_rdoc:
|
@@ -1,77 +0,0 @@
|
|
1
|
-
require 'concurrent/actor/simple_actor_ref'
|
2
|
-
|
3
|
-
module Concurrent
|
4
|
-
|
5
|
-
# Actor-based concurrency is all the rage in some circles. Originally described in
|
6
|
-
# 1973, the actor model is a paradigm for creating asynchronous, concurrent objects
|
7
|
-
# that is becoming increasingly popular. Much has changed since actors were first
|
8
|
-
# written about four decades ago, which has led to a serious fragmentation within
|
9
|
-
# the actor community. There is *no* universally accepted, strict definition of
|
10
|
-
# "actor" and actor implementations differ widely between languages and libraries.
|
11
|
-
#
|
12
|
-
# A good definition of "actor" is:
|
13
|
-
#
|
14
|
-
# An independent, concurrent, single-purpose, computational entity that communicates exclusively via message passing.
|
15
|
-
#
|
16
|
-
# The actor framework in this library is heavily influenced by the Akka toolkit,
|
17
|
-
# with additional inspiration from Erlang and Scala. Unlike many of the abstractions
|
18
|
-
# in this library, `ActorContext` takes an *object-oriented* approach to asynchronous
|
19
|
-
# concurrency, rather than a *functional programming* approach.
|
20
|
-
#
|
21
|
-
# Creating an actor class is achieved by including the `ActorContext` module
|
22
|
-
# within a standard Ruby class. One `ActorContext` is mixed in, however, everything
|
23
|
-
# changes. Objects of the class can no longer be instanced with the `#new` method.
|
24
|
-
# Instead, the various factor methods, such as `#spawn`, must be used. These factory
|
25
|
-
# methods do not return direct references to the actor object. Instead they return
|
26
|
-
# objects of one of the `ActorRef` subclasses. The `ActorRef` objects encapsulate
|
27
|
-
# actor objects. This encapsulation is necessary to prevent synchronous method calls
|
28
|
-
# froom being made against the actors. It also allows the messaging and lifecycle
|
29
|
-
# behavior to be implemented within the `ActorRef` subclasses, allowing for better
|
30
|
-
# separation of responsibility.
|
31
|
-
#
|
32
|
-
# @see Concurrent::ActorRef
|
33
|
-
#
|
34
|
-
# @see http://akka.io/
|
35
|
-
# @see http://www.erlang.org/doc/getting_started/conc_prog.html
|
36
|
-
# @see http://www.scala-lang.org/api/current/index.html#scala.actors.Actor
|
37
|
-
#
|
38
|
-
# @see http://doc.akka.io/docs/akka/snapshot/general/supervision.html#What_Restarting_Means What Restarting Means
|
39
|
-
# @see http://doc.akka.io/docs/akka/snapshot/general/supervision.html#What_Lifecycle_Monitoring_Means What Lifecycle Monitoring Means
|
40
|
-
module ActorContext
|
41
|
-
|
42
|
-
# Callback method called by the `ActorRef` which encapsulates the actor instance.
|
43
|
-
def on_start
|
44
|
-
end
|
45
|
-
|
46
|
-
# Callback method called by the `ActorRef` which encapsulates the actor instance.
|
47
|
-
def on_shutdown
|
48
|
-
end
|
49
|
-
|
50
|
-
# Callback method called by the `ActorRef` which encapsulates the actor instance.
|
51
|
-
#
|
52
|
-
# @param [Time] time the date/time at which the error occurred
|
53
|
-
# @param [Array] message the message that caused the error
|
54
|
-
# @param [Exception] exception the exception object that was raised
|
55
|
-
def on_error(time, message, exception)
|
56
|
-
end
|
57
|
-
|
58
|
-
def self.included(base)
|
59
|
-
|
60
|
-
class << base
|
61
|
-
|
62
|
-
# Create a single, unregistered actor. The actor will run on its own, dedicated
|
63
|
-
# thread. The thread will be started the first time a message is post to the actor.
|
64
|
-
# Should the thread ever die it will be restarted the next time a message is post.
|
65
|
-
#
|
66
|
-
# @param [Hash] opts the options defining actor behavior
|
67
|
-
# @option opts [Array] :args (`nil`) arguments to be passed to the actor constructor
|
68
|
-
#
|
69
|
-
# @return [SimpleActorRef] the `ActorRef` encapsulating the actor
|
70
|
-
def spawn(opts = {})
|
71
|
-
args = opts.fetch(:args, [])
|
72
|
-
Concurrent::SimpleActorRef.new(self.new(*args), opts)
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
@@ -1,67 +0,0 @@
|
|
1
|
-
module Concurrent
|
2
|
-
|
3
|
-
# Base class for classes that encapsulate `ActorContext` objects.
|
4
|
-
#
|
5
|
-
# @see Concurrent::ActorContext
|
6
|
-
module ActorRef
|
7
|
-
|
8
|
-
# @!method post(*msg, &block)
|
9
|
-
#
|
10
|
-
# Send a message and return a future which will eventually be updated
|
11
|
-
# with the result of the operation. An optional callback block can be
|
12
|
-
# given which will be called once the operation is complete. Although
|
13
|
-
# it is possible to use a callback block and also interrogate the
|
14
|
-
# returned future it is a good practice to do one or the other.
|
15
|
-
#
|
16
|
-
# @param [Array] msg One or more elements of the message
|
17
|
-
#
|
18
|
-
# @yield a callback operation to be performed when the operation is complete.
|
19
|
-
# @yieldparam [Time] time the date/time at which the error occurred
|
20
|
-
# @yieldparam [Object] result the result of message processing or `nil` on error
|
21
|
-
# @yieldparam [Exception] exception the exception object that was raised or `nil` on success
|
22
|
-
#
|
23
|
-
# @return [IVar] a future that will eventually contain the result of message processing
|
24
|
-
|
25
|
-
# @!method post!(timeout, *msg)
|
26
|
-
# Send a message synchronously and block awaiting the response.
|
27
|
-
#
|
28
|
-
# @param [Integer] timeout the maximum number of seconds to block waiting
|
29
|
-
# for a response
|
30
|
-
# @param [Array] msg One or more elements of the message
|
31
|
-
#
|
32
|
-
# @return [Object] the result of successful message processing
|
33
|
-
#
|
34
|
-
# @raise [Concurrent::TimeoutError] if a timeout occurs
|
35
|
-
# @raise [Exception] an exception which occurred during message processing
|
36
|
-
|
37
|
-
# @!method running?()
|
38
|
-
# Is the actor running and processing messages?
|
39
|
-
# @return [Boolean] `true` if running else `false`
|
40
|
-
|
41
|
-
# @!method shutdown?()
|
42
|
-
# Is the actor shutdown and no longer processing messages?
|
43
|
-
# @return [Boolean] `true` if shutdown else `false`
|
44
|
-
|
45
|
-
# @!method shutdown()
|
46
|
-
# Shutdown the actor, gracefully exit all threads, and stop processing messages.
|
47
|
-
# @return [Boolean] `true` if shutdown is successful else `false`
|
48
|
-
|
49
|
-
# @!method join(limit = nil)
|
50
|
-
# Suspend the current thread until the actor has been shutdown
|
51
|
-
# @param [Integer] limit the maximum number of seconds to block waiting for the
|
52
|
-
# actor to shutdown. Block indefinitely when `nil` or not given
|
53
|
-
# @return [Boolean] `true` if the actor shutdown before the limit expired else `false`
|
54
|
-
# @see http://www.ruby-doc.org/core-2.1.1/Thread.html#method-i-join
|
55
|
-
|
56
|
-
# Send a message and return. It's a fire-and-forget interaction.
|
57
|
-
#
|
58
|
-
# @param [Object] message a single value representing the message to be sent
|
59
|
-
# to the actor or an array of multiple message components
|
60
|
-
#
|
61
|
-
# @return [ActorRef] self
|
62
|
-
def <<(message)
|
63
|
-
post(*message)
|
64
|
-
self
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
@@ -1,94 +0,0 @@
|
|
1
|
-
require 'concurrent/actor/actor_ref'
|
2
|
-
require 'concurrent/atomic/event'
|
3
|
-
require 'concurrent/executor/single_thread_executor'
|
4
|
-
require 'concurrent/ivar'
|
5
|
-
|
6
|
-
module Concurrent
|
7
|
-
|
8
|
-
class SimpleActorRef
|
9
|
-
include ActorRef
|
10
|
-
|
11
|
-
def initialize(actor, opts = {})
|
12
|
-
@actor = actor
|
13
|
-
@mutex = Mutex.new
|
14
|
-
@one_by_one = OneByOne.new
|
15
|
-
@executor = OptionsParser::get_executor_from(opts)
|
16
|
-
@stop_event = Event.new
|
17
|
-
@reset_on_error = opts.fetch(:reset_on_error, true)
|
18
|
-
@exception_class = opts.fetch(:rescue_exception, false) ? Exception : StandardError
|
19
|
-
@args = opts.fetch(:args, []) if @reset_on_error
|
20
|
-
|
21
|
-
@actor.define_singleton_method(:shutdown, &method(:set_stop_event))
|
22
|
-
@actor.on_start
|
23
|
-
end
|
24
|
-
|
25
|
-
def running?
|
26
|
-
not @stop_event.set?
|
27
|
-
end
|
28
|
-
|
29
|
-
def shutdown?
|
30
|
-
@stop_event.set?
|
31
|
-
end
|
32
|
-
|
33
|
-
def post(*msg, &block)
|
34
|
-
raise ArgumentError.new('message cannot be empty') if msg.empty?
|
35
|
-
ivar = IVar.new
|
36
|
-
@one_by_one.post(@executor, Message.new(msg, ivar, block), &method(:process_message))
|
37
|
-
ivar
|
38
|
-
end
|
39
|
-
|
40
|
-
def post!(timeout, *msg)
|
41
|
-
raise Concurrent::TimeoutError unless timeout.nil? || timeout >= 0
|
42
|
-
ivar = self.post(*msg)
|
43
|
-
ivar.value(timeout)
|
44
|
-
if ivar.incomplete?
|
45
|
-
raise Concurrent::TimeoutError
|
46
|
-
elsif ivar.reason
|
47
|
-
raise ivar.reason
|
48
|
-
end
|
49
|
-
ivar.value
|
50
|
-
end
|
51
|
-
|
52
|
-
def shutdown
|
53
|
-
@mutex.synchronize do
|
54
|
-
return if shutdown?
|
55
|
-
@actor.on_shutdown
|
56
|
-
@stop_event.set
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def join(limit = nil)
|
61
|
-
@stop_event.wait(limit)
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
|
66
|
-
Message = Struct.new(:payload, :ivar, :callback)
|
67
|
-
|
68
|
-
def set_stop_event
|
69
|
-
@stop_event.set
|
70
|
-
end
|
71
|
-
|
72
|
-
def process_message(message)
|
73
|
-
result = ex = nil
|
74
|
-
|
75
|
-
begin
|
76
|
-
result = @actor.receive(*message.payload)
|
77
|
-
rescue @exception_class => ex
|
78
|
-
@actor.on_error(Time.now, message.payload, ex)
|
79
|
-
if @reset_on_error
|
80
|
-
@mutex.synchronize{ @actor = @actor.class.new(*@args) }
|
81
|
-
end
|
82
|
-
ensure
|
83
|
-
now = Time.now
|
84
|
-
message.ivar.complete(ex.nil?, result, ex)
|
85
|
-
|
86
|
-
begin
|
87
|
-
message.callback.call(now, result, ex) if message.callback
|
88
|
-
rescue @exception_class => ex
|
89
|
-
# suppress
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
Binary file
|
@@ -1,29 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module Concurrent
|
4
|
-
|
5
|
-
describe ActorContext do
|
6
|
-
|
7
|
-
let(:described_class) do
|
8
|
-
Class.new do
|
9
|
-
include ActorContext
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
context 'callbacks' do
|
14
|
-
|
15
|
-
subject { described_class.send(:new) }
|
16
|
-
|
17
|
-
specify { subject.should respond_to :on_start }
|
18
|
-
|
19
|
-
specify { subject.should respond_to :on_shutdown }
|
20
|
-
end
|
21
|
-
|
22
|
-
context '#spawn' do
|
23
|
-
|
24
|
-
it 'returns an ActorRef' do
|
25
|
-
described_class.spawn.should be_a ActorRef
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
@@ -1,263 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
def create_actor_test_class
|
4
|
-
Class.new do
|
5
|
-
include Concurrent::ActorContext
|
6
|
-
|
7
|
-
attr_reader :argv
|
8
|
-
|
9
|
-
def initialize(*args)
|
10
|
-
@argv = args
|
11
|
-
end
|
12
|
-
|
13
|
-
def receive(*msg)
|
14
|
-
case msg.first
|
15
|
-
when :poison
|
16
|
-
raise StandardError
|
17
|
-
when :bullet
|
18
|
-
raise Exception
|
19
|
-
when :stop
|
20
|
-
shutdown
|
21
|
-
when :terminate
|
22
|
-
Thread.current.kill
|
23
|
-
when :sleep
|
24
|
-
sleep(msg.last)
|
25
|
-
when :check
|
26
|
-
msg[1].set(msg.last)
|
27
|
-
else
|
28
|
-
msg.first
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
share_examples_for :actor_ref do
|
35
|
-
|
36
|
-
after(:each) do
|
37
|
-
subject.shutdown
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'includes ActorRef' do
|
41
|
-
subject.should be_a Concurrent::ActorRef
|
42
|
-
end
|
43
|
-
|
44
|
-
context 'running and shutdown' do
|
45
|
-
|
46
|
-
specify { subject.should respond_to :shutdown }
|
47
|
-
|
48
|
-
specify { subject.should be_running }
|
49
|
-
|
50
|
-
specify { subject.should_not be_shutdown }
|
51
|
-
|
52
|
-
specify do
|
53
|
-
subject.shutdown
|
54
|
-
sleep(0.1)
|
55
|
-
subject.should be_shutdown
|
56
|
-
end
|
57
|
-
|
58
|
-
it 'defines a shutdown method on the actor(s)' do
|
59
|
-
subject << :foo
|
60
|
-
subject << :stop
|
61
|
-
sleep(0.1)
|
62
|
-
subject.should be_shutdown
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
context '#post' do
|
67
|
-
|
68
|
-
it 'raises an exception when the message is empty' do
|
69
|
-
expect {
|
70
|
-
subject.post
|
71
|
-
}.to raise_error(ArgumentError)
|
72
|
-
end
|
73
|
-
|
74
|
-
it 'returns an IVar' do
|
75
|
-
subject.post(:foo).should be_a Concurrent::IVar
|
76
|
-
end
|
77
|
-
|
78
|
-
it 'fulfills the IVar when message is processed' do
|
79
|
-
ivar = subject.post(:foo)
|
80
|
-
sleep(0.1)
|
81
|
-
ivar.should be_fulfilled
|
82
|
-
ivar.value.should eq :foo
|
83
|
-
end
|
84
|
-
|
85
|
-
it 'rejects the IVar when message processing fails' do
|
86
|
-
ivar = subject.post(:poison)
|
87
|
-
sleep(0.1)
|
88
|
-
ivar.should be_rejected
|
89
|
-
ivar.reason.should be_a StandardError
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
context '#<<' do
|
94
|
-
|
95
|
-
it 'posts the message' do
|
96
|
-
ivar = Concurrent::IVar.new
|
97
|
-
subject << [:check, ivar, :foo]
|
98
|
-
ivar.value(0.1).should eq :foo
|
99
|
-
end
|
100
|
-
|
101
|
-
it 'returns self' do
|
102
|
-
expected = subject
|
103
|
-
result = subject << [1,2,3,4]
|
104
|
-
result.should eq expected
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
context '#post with callback' do
|
109
|
-
|
110
|
-
specify 'on success calls the callback with time and value' do
|
111
|
-
expected_value = expected_reason = nil
|
112
|
-
subject.post(:foo) do |time, value, reason|
|
113
|
-
expected_value = value
|
114
|
-
expected_reason = reason
|
115
|
-
end
|
116
|
-
sleep(0.1)
|
117
|
-
|
118
|
-
expected_value.should eq :foo
|
119
|
-
expected_reason.should be_nil
|
120
|
-
end
|
121
|
-
|
122
|
-
specify 'on failure calls the callback with time and reason' do
|
123
|
-
expected_value = expected_reason = nil
|
124
|
-
subject.post(:poison) do |time, value, reason|
|
125
|
-
expected_value = value
|
126
|
-
expected_reason = reason
|
127
|
-
end
|
128
|
-
sleep(0.1)
|
129
|
-
|
130
|
-
expected_value.should be_nil
|
131
|
-
expected_reason.should be_a StandardError
|
132
|
-
end
|
133
|
-
|
134
|
-
it 'supresses exceptions thrown by the callback' do
|
135
|
-
expected = nil
|
136
|
-
subject.post(:foo){|time, value, reason| raise StandardError }
|
137
|
-
sleep(0.1)
|
138
|
-
|
139
|
-
subject.post(:bar){|time, value, reason| expected = value }
|
140
|
-
sleep(0.1)
|
141
|
-
|
142
|
-
expected.should eq :bar
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
context '#post!' do
|
147
|
-
|
148
|
-
it 'raises an exception when the message is empty' do
|
149
|
-
expect {
|
150
|
-
subject.post!(1)
|
151
|
-
}.to raise_error(ArgumentError)
|
152
|
-
end
|
153
|
-
|
154
|
-
it 'blocks for up to the given number of seconds' do
|
155
|
-
start = Time.now.to_f
|
156
|
-
begin
|
157
|
-
subject.post!(1, :sleep, 2)
|
158
|
-
rescue
|
159
|
-
end
|
160
|
-
delta = Time.now.to_f - start
|
161
|
-
delta.should >= 1
|
162
|
-
delta.should <= 2
|
163
|
-
end
|
164
|
-
|
165
|
-
it 'blocks forever when the timeout is nil' do
|
166
|
-
start = Time.now.to_f
|
167
|
-
subject.post!(nil, :sleep, 1)
|
168
|
-
delta = Time.now.to_f - start
|
169
|
-
delta.should > 1
|
170
|
-
end
|
171
|
-
|
172
|
-
it 'raises a TimeoutError when timeout is zero' do
|
173
|
-
expect {
|
174
|
-
subject.post!(0, :foo)
|
175
|
-
}.to raise_error(Concurrent::TimeoutError)
|
176
|
-
end
|
177
|
-
|
178
|
-
it 'raises a TimeoutError when the timeout is reached' do
|
179
|
-
expect {
|
180
|
-
subject.post!(1, :sleep, 10)
|
181
|
-
}.to raise_error(Concurrent::TimeoutError)
|
182
|
-
end
|
183
|
-
|
184
|
-
it 'returns the result of success processing' do
|
185
|
-
subject.post!(1, :foo).should eq :foo
|
186
|
-
end
|
187
|
-
|
188
|
-
it 'bubbles exceptions thrown during processing' do
|
189
|
-
expect {
|
190
|
-
subject.post!(1, :poison)
|
191
|
-
}.to raise_error(StandardError)
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
|
-
context '#join' do
|
196
|
-
|
197
|
-
it 'blocks until shutdown when no limit is given' do
|
198
|
-
start = Time.now
|
199
|
-
subject << :foo # start the actor's thread
|
200
|
-
Thread.new{ sleep(1); subject.shutdown }
|
201
|
-
subject.join
|
202
|
-
stop = Time.now
|
203
|
-
|
204
|
-
subject.should be_shutdown
|
205
|
-
stop.should >= start + 1
|
206
|
-
stop.should <= start + 2
|
207
|
-
end
|
208
|
-
|
209
|
-
it 'blocks for no more than the given number of seconds' do
|
210
|
-
start = Time.now
|
211
|
-
subject << :foo # start the actor's thread
|
212
|
-
Thread.new{ sleep(5); subject.shutdown }
|
213
|
-
subject.join(1)
|
214
|
-
stop = Time.now
|
215
|
-
|
216
|
-
stop.should >= start + 1
|
217
|
-
stop.should <= start + 2
|
218
|
-
end
|
219
|
-
|
220
|
-
it 'returns true when shutdown has completed before timeout' do
|
221
|
-
subject << :foo # start the actor's thread
|
222
|
-
Thread.new{ sleep(1); subject.shutdown }
|
223
|
-
subject.join.should be_true
|
224
|
-
end
|
225
|
-
|
226
|
-
it 'returns false on timeout' do
|
227
|
-
subject << :foo # start the actor's thread
|
228
|
-
Thread.new{ sleep(5); subject.shutdown }
|
229
|
-
subject.join(1).should be_false
|
230
|
-
end
|
231
|
-
|
232
|
-
it 'returns immediately when already shutdown' do
|
233
|
-
start = Time.now
|
234
|
-
subject << :foo # start the actor's thread
|
235
|
-
sleep(0.1)
|
236
|
-
subject.shutdown
|
237
|
-
sleep(0.1)
|
238
|
-
|
239
|
-
start = Time.now
|
240
|
-
subject.join
|
241
|
-
Time.now.should >= start
|
242
|
-
Time.now.should <= start + 0.1
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
context '#on_error' do
|
247
|
-
|
248
|
-
specify 'is not called on success' do
|
249
|
-
actor = subject.instance_variable_get(:@actor)
|
250
|
-
actor.should_not_receive(:on_error).with(any_args)
|
251
|
-
subject.post(:foo)
|
252
|
-
sleep(0.1)
|
253
|
-
end
|
254
|
-
|
255
|
-
specify 'is called when a message raises an exception' do
|
256
|
-
actor = subject.instance_variable_get(:@actor)
|
257
|
-
actor.should_receive(:on_error).
|
258
|
-
with(anything, [:poison], an_instance_of(StandardError))
|
259
|
-
subject.post(:poison)
|
260
|
-
sleep(0.1)
|
261
|
-
end
|
262
|
-
end
|
263
|
-
end
|