celluloid 0.15.2 → 0.16.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/LICENSE.txt +20 -0
- data/README.md +25 -2
- data/lib/celluloid/actor.rb +88 -147
- data/lib/celluloid/actor_system.rb +107 -0
- data/lib/celluloid/call_chain.rb +1 -1
- data/lib/celluloid/calls.rb +16 -16
- data/lib/celluloid/cell.rb +89 -0
- data/lib/celluloid/condition.rb +25 -8
- data/lib/celluloid/cpu_counter.rb +28 -18
- data/lib/celluloid/evented_mailbox.rb +10 -16
- data/lib/celluloid/exceptions.rb +23 -0
- data/lib/celluloid/future.rb +1 -1
- data/lib/celluloid/handlers.rb +41 -0
- data/lib/celluloid/internal_pool.rb +49 -40
- data/lib/celluloid/logger.rb +30 -0
- data/lib/celluloid/logging/incident_logger.rb +1 -1
- data/lib/celluloid/mailbox.rb +35 -31
- data/lib/celluloid/method.rb +8 -0
- data/lib/celluloid/pool_manager.rb +19 -2
- data/lib/celluloid/probe.rb +73 -0
- data/lib/celluloid/properties.rb +2 -2
- data/lib/celluloid/proxies/actor_proxy.rb +9 -41
- data/lib/celluloid/proxies/cell_proxy.rb +68 -0
- data/lib/celluloid/proxies/sync_proxy.rb +1 -1
- data/lib/celluloid/receivers.rb +5 -13
- data/lib/celluloid/registry.rb +1 -8
- data/{spec/support → lib/celluloid/rspec}/actor_examples.rb +58 -15
- data/{spec/support → lib/celluloid/rspec}/mailbox_examples.rb +9 -3
- data/{spec/support → lib/celluloid/rspec}/task_examples.rb +2 -0
- data/lib/celluloid/rspec.rb +4 -3
- data/lib/celluloid/stack_dump.rb +34 -11
- data/lib/celluloid/supervision_group.rb +26 -14
- data/lib/celluloid/tasks/task_fiber.rb +6 -0
- data/lib/celluloid/tasks/task_thread.rb +2 -1
- data/lib/celluloid/tasks.rb +28 -9
- data/lib/celluloid/thread_handle.rb +2 -2
- data/lib/celluloid.rb +68 -73
- data/spec/celluloid/actor_spec.rb +1 -1
- data/spec/celluloid/actor_system_spec.rb +69 -0
- data/spec/celluloid/block_spec.rb +1 -1
- data/spec/celluloid/calls_spec.rb +1 -1
- data/spec/celluloid/condition_spec.rb +14 -3
- data/spec/celluloid/cpu_counter_spec.rb +82 -0
- data/spec/celluloid/fsm_spec.rb +1 -1
- data/spec/celluloid/future_spec.rb +1 -1
- data/spec/celluloid/notifications_spec.rb +1 -1
- data/spec/celluloid/pool_spec.rb +34 -1
- data/spec/celluloid/probe_spec.rb +121 -0
- data/spec/celluloid/registry_spec.rb +6 -6
- data/spec/celluloid/stack_dump_spec.rb +37 -8
- data/spec/celluloid/supervision_group_spec.rb +7 -1
- data/spec/celluloid/supervisor_spec.rb +12 -1
- data/spec/celluloid/tasks/task_fiber_spec.rb +1 -1
- data/spec/celluloid/tasks/task_thread_spec.rb +1 -1
- data/spec/celluloid/thread_handle_spec.rb +7 -3
- data/spec/celluloid/timer_spec.rb +48 -0
- data/spec/spec_helper.rb +20 -7
- metadata +51 -26
- /data/{spec/support → lib/celluloid/rspec}/example_actor_class.rb +0 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
require 'celluloid'
|
|
2
|
+
|
|
3
|
+
$CELLULOID_MONITORING = true
|
|
4
|
+
|
|
5
|
+
module Celluloid
|
|
6
|
+
class Probe
|
|
7
|
+
include Celluloid
|
|
8
|
+
include Celluloid::Notifications
|
|
9
|
+
|
|
10
|
+
NOTIFICATIONS_TOPIC_BASE = 'celluloid.events.%s'
|
|
11
|
+
INITIAL_EVENTS = Queue.new
|
|
12
|
+
|
|
13
|
+
class << self
|
|
14
|
+
def run
|
|
15
|
+
# spawn the actor if not found
|
|
16
|
+
supervise_as(:probe_actor) unless Actor[:probe_actor] && Actor[:probe_actor].alive?
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def actor_created(actor)
|
|
20
|
+
trigger_event(:actor_created, actor)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def actor_named(actor)
|
|
24
|
+
trigger_event(:actor_named, actor)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def actor_died(actor)
|
|
28
|
+
trigger_event(:actor_died, actor)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def actors_linked(a, b)
|
|
32
|
+
a = find_actor(a)
|
|
33
|
+
b = find_actor(b)
|
|
34
|
+
trigger_event(:actors_linked, a, b)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
private
|
|
38
|
+
|
|
39
|
+
def trigger_event(name, *args)
|
|
40
|
+
return unless $CELLULOID_MONITORING
|
|
41
|
+
probe_actor = Actor[:probe_actor]
|
|
42
|
+
if probe_actor
|
|
43
|
+
probe_actor.async.dispatch_event(name, args)
|
|
44
|
+
else
|
|
45
|
+
INITIAL_EVENTS << [name, args]
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def find_actor(obj)
|
|
50
|
+
if obj.__send__(:class) == Actor
|
|
51
|
+
obj
|
|
52
|
+
elsif owner = obj.instance_variable_get(OWNER_IVAR)
|
|
53
|
+
owner
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def initialize
|
|
59
|
+
async.first_run
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def first_run
|
|
63
|
+
until INITIAL_EVENTS.size == 0
|
|
64
|
+
event = INITIAL_EVENTS.pop
|
|
65
|
+
dispatch_event(*event)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def dispatch_event(cmd, args)
|
|
70
|
+
publish(NOTIFICATIONS_TOPIC_BASE % cmd, args)
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
data/lib/celluloid/properties.rb
CHANGED
|
@@ -9,7 +9,7 @@ module Celluloid
|
|
|
9
9
|
|
|
10
10
|
ancestors.first.send(:define_singleton_method, name) do |value = nil, *extra|
|
|
11
11
|
if value
|
|
12
|
-
value = value ? [value, *extra] : [] if multi
|
|
12
|
+
value = value ? [value, *send(name), *extra].uniq : [] if multi
|
|
13
13
|
instance_variable_set(ivar_name, value)
|
|
14
14
|
elsif instance_variables.include?(ivar_name)
|
|
15
15
|
instance_variable_get(ivar_name)
|
|
@@ -21,4 +21,4 @@ module Celluloid
|
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
end
|
|
24
|
-
end
|
|
24
|
+
end
|
|
@@ -1,59 +1,27 @@
|
|
|
1
1
|
module Celluloid
|
|
2
|
-
# A proxy
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
attr_reader :thread
|
|
2
|
+
# A proxy which controls the Actor lifecycle
|
|
3
|
+
class ActorProxy < AbstractProxy
|
|
4
|
+
attr_reader :thread, :mailbox
|
|
6
5
|
|
|
7
6
|
# Used for reflecting on proxy objects themselves
|
|
8
7
|
def __class__; ActorProxy; end
|
|
9
8
|
|
|
10
|
-
def initialize(
|
|
11
|
-
@thread =
|
|
12
|
-
|
|
13
|
-
super(actor.mailbox, actor.subject.class.to_s)
|
|
14
|
-
@sync_proxy = SyncProxy.new(@mailbox, @klass)
|
|
15
|
-
@async_proxy = AsyncProxy.new(@mailbox, @klass)
|
|
16
|
-
@future_proxy = FutureProxy.new(@mailbox, @klass)
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def _send_(meth, *args, &block)
|
|
20
|
-
method_missing :__send__, meth, *args, &block
|
|
9
|
+
def initialize(thread, mailbox)
|
|
10
|
+
@thread = thread
|
|
11
|
+
@mailbox = mailbox
|
|
21
12
|
end
|
|
22
13
|
|
|
23
14
|
def inspect
|
|
24
|
-
|
|
15
|
+
# TODO: use a system event to fetch actor state: tasks?
|
|
16
|
+
"#<Celluloid::ActorProxy(#{@mailbox.address}) alive>"
|
|
25
17
|
rescue DeadActorError
|
|
26
|
-
"#<Celluloid::ActorProxy(#{@
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
def method(name)
|
|
30
|
-
Method.new(self, name)
|
|
18
|
+
"#<Celluloid::ActorProxy(#{@mailbox.address}) dead>"
|
|
31
19
|
end
|
|
32
20
|
|
|
33
21
|
def alive?
|
|
34
22
|
@mailbox.alive?
|
|
35
23
|
end
|
|
36
24
|
|
|
37
|
-
alias_method :sync, :method_missing
|
|
38
|
-
|
|
39
|
-
# Obtain an async proxy or explicitly invoke a named async method
|
|
40
|
-
def async(method_name = nil, *args, &block)
|
|
41
|
-
if method_name
|
|
42
|
-
@async_proxy.method_missing method_name, *args, &block
|
|
43
|
-
else
|
|
44
|
-
@async_proxy
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
# Obtain a future proxy or explicitly invoke a named future method
|
|
49
|
-
def future(method_name = nil, *args, &block)
|
|
50
|
-
if method_name
|
|
51
|
-
@future_proxy.method_missing method_name, *args, &block
|
|
52
|
-
else
|
|
53
|
-
@future_proxy
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
25
|
# Terminate the associated actor
|
|
58
26
|
def terminate
|
|
59
27
|
terminate!
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
module Celluloid
|
|
2
|
+
# A proxy object returned from Celluloid::Actor.new/new_link which converts
|
|
3
|
+
# the normal Ruby method protocol into an inter-actor message protocol
|
|
4
|
+
class CellProxy < SyncProxy
|
|
5
|
+
# Used for reflecting on proxy objects themselves
|
|
6
|
+
def __class__; CellProxy; end
|
|
7
|
+
|
|
8
|
+
def initialize(actor_proxy, mailbox, klass)
|
|
9
|
+
super(mailbox, klass)
|
|
10
|
+
@actor_proxy = actor_proxy
|
|
11
|
+
@sync_proxy = SyncProxy.new(mailbox, klass)
|
|
12
|
+
@async_proxy = AsyncProxy.new(mailbox, klass)
|
|
13
|
+
@future_proxy = FutureProxy.new(mailbox, klass)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def _send_(meth, *args, &block)
|
|
17
|
+
method_missing :__send__, meth, *args, &block
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def inspect
|
|
21
|
+
method_missing :inspect
|
|
22
|
+
rescue DeadActorError
|
|
23
|
+
"#<Celluloid::CellProxy(#{@klass}) dead>"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def method(name)
|
|
27
|
+
Method.new(self, name)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
alias_method :sync, :method_missing
|
|
31
|
+
|
|
32
|
+
# Obtain an async proxy or explicitly invoke a named async method
|
|
33
|
+
def async(method_name = nil, *args, &block)
|
|
34
|
+
if method_name
|
|
35
|
+
@async_proxy.method_missing method_name, *args, &block
|
|
36
|
+
else
|
|
37
|
+
@async_proxy
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Obtain a future proxy or explicitly invoke a named future method
|
|
42
|
+
def future(method_name = nil, *args, &block)
|
|
43
|
+
if method_name
|
|
44
|
+
@future_proxy.method_missing method_name, *args, &block
|
|
45
|
+
else
|
|
46
|
+
@future_proxy
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def alive?
|
|
51
|
+
@actor_proxy.alive?
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def thread
|
|
55
|
+
@actor_proxy.thread
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Terminate the associated actor
|
|
59
|
+
def terminate
|
|
60
|
+
@actor_proxy.terminate
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Terminate the associated actor asynchronously
|
|
64
|
+
def terminate!
|
|
65
|
+
@actor_proxy.terminate!
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
@@ -15,7 +15,7 @@ module Celluloid
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def respond_to?(meth, include_private = false)
|
|
18
|
-
__class__.instance_methods.include?(meth) ||
|
|
18
|
+
__class__.instance_methods.include?(meth) || method_missing(:respond_to?, meth, include_private)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def method_missing(meth, *args, &block)
|
data/lib/celluloid/receivers.rb
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
require 'set'
|
|
2
|
+
|
|
2
3
|
require 'timers'
|
|
3
4
|
|
|
4
5
|
module Celluloid
|
|
5
6
|
# Allow methods to directly interact with the actor protocol
|
|
6
7
|
class Receivers
|
|
7
|
-
def initialize
|
|
8
|
+
def initialize(timers)
|
|
8
9
|
@receivers = Set.new
|
|
9
|
-
@timers =
|
|
10
|
+
@timers = timers
|
|
10
11
|
end
|
|
11
12
|
|
|
12
13
|
# Receive an asynchronous message
|
|
@@ -28,24 +29,15 @@ module Celluloid
|
|
|
28
29
|
end
|
|
29
30
|
end
|
|
30
31
|
|
|
31
|
-
# How long to wait until the next timer fires
|
|
32
|
-
def wait_interval
|
|
33
|
-
@timers.wait_interval
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# Fire any pending timers
|
|
37
|
-
def fire_timers
|
|
38
|
-
@timers.fire
|
|
39
|
-
end
|
|
40
|
-
|
|
41
32
|
# Handle incoming messages
|
|
42
33
|
def handle_message(message)
|
|
43
34
|
receiver = @receivers.find { |r| r.match(message) }
|
|
44
35
|
return unless receiver
|
|
45
36
|
|
|
46
37
|
@receivers.delete receiver
|
|
47
|
-
|
|
38
|
+
receiver.timer.cancel if receiver.timer
|
|
48
39
|
receiver.resume message
|
|
40
|
+
message
|
|
49
41
|
end
|
|
50
42
|
end
|
|
51
43
|
|
data/lib/celluloid/registry.rb
CHANGED
|
@@ -3,10 +3,6 @@ require 'thread'
|
|
|
3
3
|
module Celluloid
|
|
4
4
|
# The Registry allows us to refer to specific actors by human-meaningful names
|
|
5
5
|
class Registry
|
|
6
|
-
class << self
|
|
7
|
-
attr_reader :root
|
|
8
|
-
end
|
|
9
|
-
|
|
10
6
|
def initialize
|
|
11
7
|
@registry = {}
|
|
12
8
|
@registry_lock = Mutex.new
|
|
@@ -15,7 +11,7 @@ module Celluloid
|
|
|
15
11
|
# Register an Actor
|
|
16
12
|
def []=(name, actor)
|
|
17
13
|
actor_singleton = class << actor; self; end
|
|
18
|
-
unless actor_singleton.ancestors.include?
|
|
14
|
+
unless actor_singleton.ancestors.include? AbstractProxy
|
|
19
15
|
raise TypeError, "not an actor"
|
|
20
16
|
end
|
|
21
17
|
|
|
@@ -57,8 +53,5 @@ module Celluloid
|
|
|
57
53
|
end
|
|
58
54
|
hash
|
|
59
55
|
end
|
|
60
|
-
|
|
61
|
-
# Create the default registry
|
|
62
|
-
@root = new
|
|
63
56
|
end
|
|
64
57
|
end
|
|
@@ -65,6 +65,19 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
|
|
|
65
65
|
method.arity.should be(1)
|
|
66
66
|
end
|
|
67
67
|
|
|
68
|
+
it "supports #name calls via #method" do
|
|
69
|
+
method = actor_class.new("Troy McClure").method(:greet)
|
|
70
|
+
method.name.should == :greet
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it "supports #parameters via #method" do
|
|
74
|
+
method = actor_class.new("Troy McClure").method(:greet)
|
|
75
|
+
method.parameters.should == []
|
|
76
|
+
|
|
77
|
+
method = actor_class.new("Troy McClure").method(:change_name)
|
|
78
|
+
method.parameters.should == [[:req, :new_name]]
|
|
79
|
+
end
|
|
80
|
+
|
|
68
81
|
it "supports future(:method) syntax for synchronous future calls" do
|
|
69
82
|
actor = actor_class.new "Troy McClure"
|
|
70
83
|
future = actor.future :greet
|
|
@@ -148,7 +161,6 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
|
|
|
148
161
|
end
|
|
149
162
|
end
|
|
150
163
|
|
|
151
|
-
Celluloid.logger = double.as_null_object
|
|
152
164
|
Celluloid.logger.should_receive(:warn).with(/Dangerously suspending task: type=:call, meta={:method_name=>:initialize}, status=:sleeping/)
|
|
153
165
|
|
|
154
166
|
actor = klass.new
|
|
@@ -175,7 +187,6 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
|
|
|
175
187
|
end
|
|
176
188
|
end
|
|
177
189
|
|
|
178
|
-
Celluloid.logger = double.as_null_object
|
|
179
190
|
Celluloid.logger.should_receive(:warn).with(/Dangerously suspending task: type=:finalizer, meta={:method_name=>:cleanup}, status=:sleeping/)
|
|
180
191
|
|
|
181
192
|
actor = klass.new
|
|
@@ -221,7 +232,7 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
|
|
|
221
232
|
|
|
222
233
|
it "inspects properly" do
|
|
223
234
|
actor = actor_class.new "Troy McClure"
|
|
224
|
-
actor.inspect.should match(/Celluloid::
|
|
235
|
+
actor.inspect.should match(/Celluloid::CellProxy\(/)
|
|
225
236
|
actor.inspect.should match(/#{actor_class}/)
|
|
226
237
|
actor.inspect.should include('@name="Troy McClure"')
|
|
227
238
|
actor.inspect.should_not include("@celluloid")
|
|
@@ -230,7 +241,7 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
|
|
|
230
241
|
it "inspects properly when dead" do
|
|
231
242
|
actor = actor_class.new "Troy McClure"
|
|
232
243
|
actor.terminate
|
|
233
|
-
actor.inspect.should match(/Celluloid::
|
|
244
|
+
actor.inspect.should match(/Celluloid::CellProxy\(/)
|
|
234
245
|
actor.inspect.should match(/#{actor_class}/)
|
|
235
246
|
actor.inspect.should include('dead')
|
|
236
247
|
end
|
|
@@ -252,7 +263,7 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
|
|
|
252
263
|
itchy.other = scratchy
|
|
253
264
|
|
|
254
265
|
inspection = itchy.inspect
|
|
255
|
-
inspection.should match(/Celluloid::
|
|
266
|
+
inspection.should match(/Celluloid::CellProxy\(/)
|
|
256
267
|
inspection.should include("...")
|
|
257
268
|
end
|
|
258
269
|
|
|
@@ -274,6 +285,31 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
|
|
|
274
285
|
actor.send('foo').should eq('oof')
|
|
275
286
|
end
|
|
276
287
|
|
|
288
|
+
context "when executing under JRuby" do
|
|
289
|
+
let(:klass) {
|
|
290
|
+
Class.new do
|
|
291
|
+
include included_module
|
|
292
|
+
task_class task_klass
|
|
293
|
+
|
|
294
|
+
def current_thread_name
|
|
295
|
+
java_thread.get_name
|
|
296
|
+
end
|
|
297
|
+
|
|
298
|
+
def java_thread
|
|
299
|
+
Thread.current.to_java.getNativeThread
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
it "sets execution info" do
|
|
305
|
+
klass.new.current_thread_name.should == "Class#current_thread_name"
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
it "unsets execution info after task completion" do
|
|
309
|
+
klass.new.java_thread.get_name.should == "<unused>"
|
|
310
|
+
end
|
|
311
|
+
end if RUBY_PLATFORM == "java"
|
|
312
|
+
|
|
277
313
|
context "mocking methods" do
|
|
278
314
|
let(:actor) { actor_class.new "Troy McClure" }
|
|
279
315
|
|
|
@@ -300,27 +336,27 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
|
|
|
300
336
|
end
|
|
301
337
|
|
|
302
338
|
it "includes both sender and receiver in exception traces" do
|
|
303
|
-
|
|
339
|
+
example_receiver = Class.new do
|
|
304
340
|
include included_module
|
|
305
341
|
task_class task_klass
|
|
306
342
|
|
|
307
|
-
|
|
343
|
+
define_method(:receiver_method) do
|
|
308
344
|
raise ExampleCrash, "the spec purposely crashed me :("
|
|
309
345
|
end
|
|
310
346
|
end
|
|
311
347
|
|
|
312
|
-
|
|
348
|
+
excample_caller = Class.new do
|
|
313
349
|
include included_module
|
|
314
350
|
task_class task_klass
|
|
315
351
|
|
|
316
|
-
|
|
317
|
-
|
|
352
|
+
define_method(:sender_method) do
|
|
353
|
+
example_receiver.new.receiver_method
|
|
318
354
|
end
|
|
319
355
|
end
|
|
320
356
|
|
|
321
357
|
ex = nil
|
|
322
358
|
begin
|
|
323
|
-
|
|
359
|
+
excample_caller.new.sender_method
|
|
324
360
|
rescue => ex
|
|
325
361
|
end
|
|
326
362
|
|
|
@@ -404,6 +440,15 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
|
|
|
404
440
|
end.to raise_exception(Celluloid::DeadActorError)
|
|
405
441
|
end
|
|
406
442
|
|
|
443
|
+
it "terminates cleanly on Celluloid shutdown" do
|
|
444
|
+
Celluloid::Actor.stub(:kill).and_call_original
|
|
445
|
+
|
|
446
|
+
actor = actor_class.new "Arnold Schwarzenegger"
|
|
447
|
+
|
|
448
|
+
Celluloid.shutdown
|
|
449
|
+
Celluloid::Actor.should_not have_received(:kill)
|
|
450
|
+
end
|
|
451
|
+
|
|
407
452
|
it "raises the right DeadActorError if terminate! called after terminated" do
|
|
408
453
|
actor = actor_class.new "Arnold Schwarzenegger"
|
|
409
454
|
actor.terminate
|
|
@@ -414,8 +459,7 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
|
|
|
414
459
|
end
|
|
415
460
|
|
|
416
461
|
it "logs a warning when terminating tasks" do
|
|
417
|
-
Celluloid.logger =
|
|
418
|
-
Celluloid.logger.should_receive(:warn).with("Terminating task: type=:call, meta={:method_name=>:sleepy}, status=:sleeping")
|
|
462
|
+
Celluloid.logger.should_receive(:warn).with(/^Terminating task: type=:call, meta={:method_name=>:sleepy}, status=:sleeping\n/)
|
|
419
463
|
|
|
420
464
|
actor = actor_class.new "Arnold Schwarzenegger"
|
|
421
465
|
actor.async.sleepy 10
|
|
@@ -923,7 +967,7 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
|
|
|
923
967
|
end
|
|
924
968
|
|
|
925
969
|
context :proxy_class do
|
|
926
|
-
class ExampleProxy < Celluloid::
|
|
970
|
+
class ExampleProxy < Celluloid::CellProxy
|
|
927
971
|
def subclass_proxy?
|
|
928
972
|
true
|
|
929
973
|
end
|
|
@@ -1000,7 +1044,6 @@ shared_examples "Celluloid::Actor examples" do |included_module, task_klass|
|
|
|
1000
1044
|
|
|
1001
1045
|
context "raw message sends" do
|
|
1002
1046
|
it "logs on unhandled messages" do
|
|
1003
|
-
Celluloid.logger = double.as_null_object
|
|
1004
1047
|
Celluloid.logger.should_receive(:debug).with("Discarded message (unhandled): first")
|
|
1005
1048
|
|
|
1006
1049
|
actor = actor_class.new "Irma Gladden"
|
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
shared_context "a Celluloid Mailbox" do
|
|
2
|
+
after do
|
|
3
|
+
Celluloid.logger.stub(:debug)
|
|
4
|
+
subject.shutdown if subject.alive?
|
|
5
|
+
end
|
|
6
|
+
|
|
2
7
|
it "receives messages" do
|
|
3
8
|
message = :ohai
|
|
4
9
|
|
|
@@ -34,7 +39,10 @@ shared_context "a Celluloid Mailbox" do
|
|
|
34
39
|
interval = 0.1
|
|
35
40
|
started_at = Time.now
|
|
36
41
|
|
|
37
|
-
|
|
42
|
+
expect do
|
|
43
|
+
subject.receive(interval) { false }
|
|
44
|
+
end.to raise_exception(Celluloid::TimeoutError)
|
|
45
|
+
|
|
38
46
|
(Time.now - started_at).should be_within(Celluloid::TIMER_QUANTUM).of interval
|
|
39
47
|
end
|
|
40
48
|
|
|
@@ -55,7 +63,6 @@ shared_context "a Celluloid Mailbox" do
|
|
|
55
63
|
end
|
|
56
64
|
|
|
57
65
|
it "logs discarded messages" do
|
|
58
|
-
Celluloid.logger = double.as_null_object
|
|
59
66
|
Celluloid.logger.should_receive(:debug).with("Discarded message (mailbox is dead): third")
|
|
60
67
|
|
|
61
68
|
subject.max_size = 2
|
|
@@ -65,7 +72,6 @@ shared_context "a Celluloid Mailbox" do
|
|
|
65
72
|
end
|
|
66
73
|
|
|
67
74
|
it "discard messages when dead" do
|
|
68
|
-
Celluloid.logger = double.as_null_object
|
|
69
75
|
Celluloid.logger.should_receive(:debug).with("Discarded message (mailbox is dead): first")
|
|
70
76
|
Celluloid.logger.should_receive(:debug).with("Discarded message (mailbox is dead): second")
|
|
71
77
|
Celluloid.logger.should_receive(:debug).with("Discarded message (mailbox is dead): third")
|
|
@@ -17,11 +17,13 @@ shared_context "a Celluloid Task" do |task_class|
|
|
|
17
17
|
subject { task_class.new(task_type, {}) { Celluloid::Task.suspend(suspend_state) } }
|
|
18
18
|
|
|
19
19
|
before :each do
|
|
20
|
+
Thread.current[:celluloid_actor_system] = Celluloid.actor_system
|
|
20
21
|
Thread.current[:celluloid_actor] = actor
|
|
21
22
|
end
|
|
22
23
|
|
|
23
24
|
after :each do
|
|
24
25
|
Thread.current[:celluloid_actor] = nil
|
|
26
|
+
Thread.current[:celluloid_actor_system] = nil
|
|
25
27
|
end
|
|
26
28
|
|
|
27
29
|
it "begins with status :new" do
|
data/lib/celluloid/rspec.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
require
|
|
2
|
-
require
|
|
3
|
-
require
|
|
1
|
+
require 'celluloid/rspec/example_actor_class'
|
|
2
|
+
require 'celluloid/rspec/actor_examples'
|
|
3
|
+
require 'celluloid/rspec/mailbox_examples'
|
|
4
|
+
require 'celluloid/rspec/task_examples'
|
|
4
5
|
|
|
5
6
|
module Celluloid
|
|
6
7
|
# Timer accuracy enforced by the tests (50ms)
|
data/lib/celluloid/stack_dump.rb
CHANGED
|
@@ -16,17 +16,21 @@ module Celluloid
|
|
|
16
16
|
|
|
17
17
|
class ActorState
|
|
18
18
|
include DisplayBacktrace
|
|
19
|
-
|
|
20
|
-
attr_accessor :subject_id, :subject_class, :name
|
|
19
|
+
attr_accessor :name, :id, :cell
|
|
21
20
|
attr_accessor :status, :tasks
|
|
22
21
|
attr_accessor :backtrace
|
|
23
22
|
|
|
24
23
|
def dump
|
|
25
24
|
string = ""
|
|
26
|
-
string << "Celluloid::Actor 0x#{
|
|
25
|
+
string << "Celluloid::Actor 0x#{id.to_s(16)}"
|
|
27
26
|
string << " [#{name}]" if name
|
|
28
27
|
string << "\n"
|
|
29
28
|
|
|
29
|
+
if cell
|
|
30
|
+
string << cell.dump
|
|
31
|
+
string << "\n"
|
|
32
|
+
end
|
|
33
|
+
|
|
30
34
|
if status == :idle
|
|
31
35
|
string << "State: Idle (waiting for messages)\n"
|
|
32
36
|
display_backtrace backtrace, string
|
|
@@ -46,12 +50,18 @@ module Celluloid
|
|
|
46
50
|
end
|
|
47
51
|
end
|
|
48
52
|
|
|
49
|
-
class
|
|
53
|
+
class CellState < Struct.new(:subject_id, :subject_class)
|
|
54
|
+
def dump
|
|
55
|
+
"Celluloid::Cell 0x#{subject_id.to_s(16)}: #{subject_class}"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
class ThreadState < Struct.new(:thread_id, :backtrace, :role)
|
|
50
60
|
include DisplayBacktrace
|
|
51
61
|
|
|
52
62
|
def dump
|
|
53
63
|
string = ""
|
|
54
|
-
string << "Thread 0x#{thread_id.to_s(16)}:\n"
|
|
64
|
+
string << "Thread 0x#{thread_id.to_s(16)} (#{role}):\n"
|
|
55
65
|
display_backtrace backtrace, string
|
|
56
66
|
string
|
|
57
67
|
end
|
|
@@ -59,7 +69,9 @@ module Celluloid
|
|
|
59
69
|
|
|
60
70
|
attr_accessor :actors, :threads
|
|
61
71
|
|
|
62
|
-
def initialize
|
|
72
|
+
def initialize(internal_pool)
|
|
73
|
+
@internal_pool = internal_pool
|
|
74
|
+
|
|
63
75
|
@actors = []
|
|
64
76
|
@threads = []
|
|
65
77
|
|
|
@@ -67,7 +79,7 @@ module Celluloid
|
|
|
67
79
|
end
|
|
68
80
|
|
|
69
81
|
def snapshot
|
|
70
|
-
|
|
82
|
+
@internal_pool.each do |thread|
|
|
71
83
|
if thread.role == :actor
|
|
72
84
|
@actors << snapshot_actor(thread.actor) if thread.actor
|
|
73
85
|
else
|
|
@@ -78,8 +90,12 @@ module Celluloid
|
|
|
78
90
|
|
|
79
91
|
def snapshot_actor(actor)
|
|
80
92
|
state = ActorState.new
|
|
81
|
-
state.
|
|
82
|
-
|
|
93
|
+
state.id = actor.object_id
|
|
94
|
+
|
|
95
|
+
# TODO: delegate to the behavior
|
|
96
|
+
if actor.behavior.is_a?(Cell)
|
|
97
|
+
state.cell = snapshot_cell(actor.behavior)
|
|
98
|
+
end
|
|
83
99
|
|
|
84
100
|
tasks = actor.tasks
|
|
85
101
|
if tasks.empty?
|
|
@@ -93,11 +109,18 @@ module Celluloid
|
|
|
93
109
|
state
|
|
94
110
|
end
|
|
95
111
|
|
|
112
|
+
def snapshot_cell(behavior)
|
|
113
|
+
state = CellState.new
|
|
114
|
+
state.subject_id = behavior.subject.object_id
|
|
115
|
+
state.subject_class = behavior.subject.class
|
|
116
|
+
state
|
|
117
|
+
end
|
|
118
|
+
|
|
96
119
|
def snapshot_thread(thread)
|
|
97
|
-
ThreadState.new(thread.object_id, thread.backtrace)
|
|
120
|
+
ThreadState.new(thread.object_id, thread.backtrace, thread.role)
|
|
98
121
|
end
|
|
99
122
|
|
|
100
|
-
def
|
|
123
|
+
def print(output = STDERR)
|
|
101
124
|
@actors.each do |actor|
|
|
102
125
|
output.print actor.dump
|
|
103
126
|
end
|