celluloid 0.13.0 → 0.14.0.pre
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 +7 -0
- data/README.md +1 -2
- data/lib/celluloid.rb +84 -32
- data/lib/celluloid/actor.rb +35 -30
- data/lib/celluloid/autostart.rb +0 -13
- data/lib/celluloid/calls.rb +71 -23
- data/lib/celluloid/core_ext.rb +3 -14
- data/lib/celluloid/cpu_counter.rb +1 -1
- data/lib/celluloid/evented_mailbox.rb +82 -0
- data/lib/celluloid/fsm.rb +2 -0
- data/lib/celluloid/future.rb +4 -4
- data/lib/celluloid/internal_pool.rb +11 -8
- data/lib/celluloid/legacy.rb +14 -13
- data/lib/celluloid/logging/incident_logger.rb +2 -2
- data/lib/celluloid/mailbox.rb +16 -0
- data/lib/celluloid/method.rb +7 -7
- data/lib/celluloid/notifications.rb +1 -1
- data/lib/celluloid/proxies/abstract_proxy.rb +1 -1
- data/lib/celluloid/proxies/actor_proxy.rb +23 -27
- data/lib/celluloid/proxies/async_proxy.rb +18 -6
- data/lib/celluloid/proxies/block_proxy.rb +29 -0
- data/lib/celluloid/proxies/future_proxy.rb +9 -3
- data/lib/celluloid/proxies/sync_proxy.rb +31 -0
- data/lib/celluloid/receivers.rb +1 -1
- data/lib/celluloid/responses.rb +13 -1
- data/lib/celluloid/stack_dump.rb +8 -5
- data/lib/celluloid/supervision_group.rb +6 -4
- data/lib/celluloid/tasks.rb +63 -2
- data/lib/celluloid/tasks/task_fiber.rb +6 -46
- data/lib/celluloid/tasks/task_thread.rb +8 -44
- data/lib/celluloid/thread.rb +82 -0
- data/lib/celluloid/thread_handle.rb +3 -2
- data/lib/celluloid/version.rb +1 -1
- data/spec/support/actor_examples.rb +116 -53
- data/spec/support/example_actor_class.rb +7 -1
- data/spec/support/mailbox_examples.rb +29 -3
- data/spec/support/task_examples.rb +11 -9
- metadata +21 -29
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e34a9a2d8dc0a227e68e1d8e5a7e4de3a6a99a5a
|
4
|
+
data.tar.gz: 784898577b1163ff5a7756bd8fb4558e105b075c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e1af2a80fa4944959773aac6b1b3c800d28a64810264e6e08b1d794ec46d40752efd8d144f7c63715acd40e8a5a9576aedc3bad6c8a59a7e4b336c0c37585373
|
7
|
+
data.tar.gz: 0215cc3ab5bb87b222c9483563c4a4c89aac8ec78f6361715cb3dd2088a4908860aafaed8ec4e519f973ba29bbdaede4722973a0c4be3e177b42997aad5401d6
|
data/README.md
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
=========
|
3
3
|
[](http://rubygems.org/gems/celluloid)
|
4
4
|
[](http://travis-ci.org/celluloid/celluloid)
|
5
|
-
[](https://gemnasium.com/celluloid/celluloid)
|
6
5
|
[](https://codeclimate.com/github/celluloid/celluloid)
|
7
6
|
[](https://coveralls.io/r/celluloid/celluloid)
|
8
7
|
|
@@ -70,7 +69,7 @@ to EventMachine (with a synchronous API instead of callback/deferrable soup)
|
|
70
69
|
is available through the [Celluloid::IO](https://github.com/celluloid/celluloid-io)
|
71
70
|
library.
|
72
71
|
|
73
|
-
Like Celluloid? [Join the Google Group](http://groups.google.com/group/celluloid-ruby)
|
72
|
+
Like Celluloid? [Join the mailing list/Google Group](http://groups.google.com/group/celluloid-ruby)
|
74
73
|
or visit us on IRC at #celluloid on freenode
|
75
74
|
|
76
75
|
### Is it any good?
|
data/lib/celluloid.rb
CHANGED
@@ -25,6 +25,11 @@ module Celluloid
|
|
25
25
|
!!Thread.current[:celluloid_actor]
|
26
26
|
end
|
27
27
|
|
28
|
+
# Retrieve the mailbox for the current thread or lazily initialize it
|
29
|
+
def mailbox
|
30
|
+
Thread.current[:celluloid_mailbox] ||= Celluloid::Mailbox.new
|
31
|
+
end
|
32
|
+
|
28
33
|
# Generate a Universally Unique Identifier
|
29
34
|
def uuid
|
30
35
|
UUID.generate
|
@@ -61,13 +66,33 @@ module Celluloid
|
|
61
66
|
# Launch default services
|
62
67
|
# FIXME: We should set up the supervision hierarchy here
|
63
68
|
def boot
|
69
|
+
internal_pool.reset
|
64
70
|
Celluloid::Notifications::Fanout.supervise_as :notifications_fanout
|
65
71
|
Celluloid::IncidentReporter.supervise_as :default_incident_reporter, STDERR
|
66
72
|
end
|
67
73
|
|
74
|
+
def register_shutdown
|
75
|
+
return if @shutdown_registered
|
76
|
+
# Terminate all actors at exit
|
77
|
+
at_exit do
|
78
|
+
if defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby" && RUBY_VERSION >= "1.9"
|
79
|
+
# workaround for MRI bug losing exit status in at_exit block
|
80
|
+
# http://bugs.ruby-lang.org/issues/5218
|
81
|
+
exit_status = $!.status if $!.is_a?(SystemExit)
|
82
|
+
Celluloid.shutdown
|
83
|
+
exit exit_status if exit_status
|
84
|
+
else
|
85
|
+
Celluloid.shutdown
|
86
|
+
end
|
87
|
+
end
|
88
|
+
@shutdown_registered = true
|
89
|
+
end
|
90
|
+
|
68
91
|
# Shut down all running actors
|
69
92
|
def shutdown
|
70
93
|
Timeout.timeout(shutdown_timeout) do
|
94
|
+
internal_pool.shutdown
|
95
|
+
|
71
96
|
actors = Actor.all
|
72
97
|
Logger.debug "Terminating #{actors.size} actors..." if actors.size > 0
|
73
98
|
|
@@ -75,14 +100,14 @@ module Celluloid
|
|
75
100
|
Supervisor.root.terminate if Supervisor.root
|
76
101
|
|
77
102
|
# Actors cannot self-terminate, you must do it for them
|
78
|
-
|
103
|
+
actors.each do |actor|
|
79
104
|
begin
|
80
105
|
actor.terminate!
|
81
106
|
rescue DeadActorError, MailboxError
|
82
107
|
end
|
83
108
|
end
|
84
109
|
|
85
|
-
|
110
|
+
actors.each do |actor|
|
86
111
|
begin
|
87
112
|
Actor.join(actor)
|
88
113
|
rescue DeadActorError, MailboxError
|
@@ -91,7 +116,7 @@ module Celluloid
|
|
91
116
|
|
92
117
|
Logger.debug "Shutdown completed cleanly"
|
93
118
|
end
|
94
|
-
rescue Timeout::Error
|
119
|
+
rescue Timeout::Error
|
95
120
|
Logger.error("Couldn't cleanly terminate all actors in #{shutdown_timeout} seconds!")
|
96
121
|
end
|
97
122
|
end
|
@@ -174,13 +199,9 @@ module Celluloid
|
|
174
199
|
# Define the mailbox class for this class
|
175
200
|
def mailbox_class(klass = nil)
|
176
201
|
if klass
|
177
|
-
|
178
|
-
elsif defined?(@mailbox_class)
|
179
|
-
@mailbox_class
|
180
|
-
elsif superclass.respond_to? :mailbox_class
|
181
|
-
superclass.mailbox_class
|
202
|
+
mailbox.class = klass
|
182
203
|
else
|
183
|
-
|
204
|
+
mailbox.class
|
184
205
|
end
|
185
206
|
end
|
186
207
|
|
@@ -213,7 +234,7 @@ module Celluloid
|
|
213
234
|
def exclusive(*methods)
|
214
235
|
if methods.empty?
|
215
236
|
@exclusive_methods = :all
|
216
|
-
elsif @exclusive_methods != :all
|
237
|
+
elsif !defined?(@exclusive_methods) || @exclusive_methods != :all
|
217
238
|
@exclusive_methods ||= Set.new
|
218
239
|
@exclusive_methods.merge methods.map(&:to_sym)
|
219
240
|
end
|
@@ -221,24 +242,53 @@ module Celluloid
|
|
221
242
|
|
222
243
|
# Mark methods as running blocks on the receiver
|
223
244
|
def execute_block_on_receiver(*methods)
|
224
|
-
|
225
|
-
|
245
|
+
receiver_block_executions.merge methods.map(&:to_sym)
|
246
|
+
end
|
247
|
+
|
248
|
+
def receiver_block_executions
|
249
|
+
@receiver_block_executions ||= Set.new([:after, :every, :receive])
|
226
250
|
end
|
227
251
|
|
228
252
|
# Configuration options for Actor#new
|
229
253
|
def actor_options
|
230
254
|
{
|
231
|
-
:mailbox =>
|
255
|
+
:mailbox => mailbox.build,
|
232
256
|
:proxy_class => proxy_class,
|
233
257
|
:task_class => task_class,
|
234
258
|
:exit_handler => exit_handler,
|
235
|
-
:exclusive_methods => defined?(@exclusive_methods) ? @exclusive_methods : nil
|
259
|
+
:exclusive_methods => defined?(@exclusive_methods) ? @exclusive_methods : nil,
|
260
|
+
:receiver_block_executions => receiver_block_executions
|
236
261
|
}
|
237
262
|
end
|
238
263
|
|
239
264
|
def ===(other)
|
240
265
|
other.kind_of? self
|
241
266
|
end
|
267
|
+
|
268
|
+
def mailbox
|
269
|
+
@mailbox_factory ||= MailboxFactory.new(self)
|
270
|
+
end
|
271
|
+
|
272
|
+
class MailboxFactory
|
273
|
+
attr_accessor :class, :max_size
|
274
|
+
|
275
|
+
def initialize(actor)
|
276
|
+
@actor = actor
|
277
|
+
@class = nil
|
278
|
+
@max_size = nil
|
279
|
+
end
|
280
|
+
|
281
|
+
def build
|
282
|
+
mailbox = mailbox_class.new
|
283
|
+
mailbox.max_size = @max_size
|
284
|
+
mailbox
|
285
|
+
end
|
286
|
+
|
287
|
+
private
|
288
|
+
def mailbox_class
|
289
|
+
@class || (@actor.superclass.respond_to?(:mailbox_class) && @actor.superclass.mailbox_class) || Celluloid::Mailbox
|
290
|
+
end
|
291
|
+
end
|
242
292
|
end
|
243
293
|
|
244
294
|
# These are methods we don't want added to the Celluloid singleton but to be
|
@@ -265,6 +315,16 @@ module Celluloid
|
|
265
315
|
@celluloid_owner != Thread.current[:celluloid_actor]
|
266
316
|
end
|
267
317
|
|
318
|
+
def tap
|
319
|
+
yield current_actor
|
320
|
+
current_actor
|
321
|
+
end
|
322
|
+
|
323
|
+
# Obtain the name of the current actor
|
324
|
+
def name
|
325
|
+
Actor.name
|
326
|
+
end
|
327
|
+
|
268
328
|
def inspect
|
269
329
|
str = "#<"
|
270
330
|
|
@@ -291,7 +351,7 @@ module Celluloid
|
|
291
351
|
# directly inside of all classes that include Celluloid
|
292
352
|
#
|
293
353
|
|
294
|
-
# Raise an exception in
|
354
|
+
# Raise an exception in sender context, but stay running
|
295
355
|
def abort(cause)
|
296
356
|
cause = case cause
|
297
357
|
when String then RuntimeError.new(cause)
|
@@ -326,11 +386,6 @@ module Celluloid
|
|
326
386
|
Thread.current[:celluloid_chain_id]
|
327
387
|
end
|
328
388
|
|
329
|
-
# Obtain the name of the current actor
|
330
|
-
def name
|
331
|
-
Actor.name
|
332
|
-
end
|
333
|
-
|
334
389
|
# Obtain the running tasks for this actor
|
335
390
|
def tasks
|
336
391
|
Thread.current[:celluloid_actor].tasks.to_a
|
@@ -377,7 +432,7 @@ module Celluloid
|
|
377
432
|
if actor
|
378
433
|
actor.receive(timeout, &block)
|
379
434
|
else
|
380
|
-
|
435
|
+
Celluloid.mailbox.receive(timeout, &block)
|
381
436
|
end
|
382
437
|
end
|
383
438
|
|
@@ -414,7 +469,7 @@ module Celluloid
|
|
414
469
|
end
|
415
470
|
|
416
471
|
# Perform a blocking or computationally intensive action inside an
|
417
|
-
# asynchronous thread pool, allowing the
|
472
|
+
# asynchronous thread pool, allowing the sender to continue processing other
|
418
473
|
# messages in its mailbox in the meantime
|
419
474
|
def defer(&block)
|
420
475
|
# This implementation relies on the present implementation of
|
@@ -424,20 +479,12 @@ module Celluloid
|
|
424
479
|
|
425
480
|
# Handle async calls within an actor itself
|
426
481
|
def async(meth = nil, *args, &block)
|
427
|
-
|
428
|
-
Actor.async Thread.current[:celluloid_actor].mailbox, meth, *args, &block
|
429
|
-
else
|
430
|
-
Thread.current[:celluloid_actor].proxy.async
|
431
|
-
end
|
482
|
+
Thread.current[:celluloid_actor].proxy.async meth, *args, &block
|
432
483
|
end
|
433
484
|
|
434
485
|
# Handle calls to future within an actor itself
|
435
486
|
def future(meth = nil, *args, &block)
|
436
|
-
|
437
|
-
Actor.future Thread.current[:celluloid_actor].mailbox, meth, *args, &block
|
438
|
-
else
|
439
|
-
Thread.current[:celluloid_actor].proxy.future
|
440
|
-
end
|
487
|
+
Thread.current[:celluloid_actor].proxy.future meth, *args, &block
|
441
488
|
end
|
442
489
|
end
|
443
490
|
|
@@ -445,6 +492,7 @@ require 'celluloid/version'
|
|
445
492
|
|
446
493
|
require 'celluloid/calls'
|
447
494
|
require 'celluloid/condition'
|
495
|
+
require 'celluloid/thread'
|
448
496
|
require 'celluloid/core_ext'
|
449
497
|
require 'celluloid/cpu_counter'
|
450
498
|
require 'celluloid/fiber'
|
@@ -453,6 +501,7 @@ require 'celluloid/internal_pool'
|
|
453
501
|
require 'celluloid/links'
|
454
502
|
require 'celluloid/logger'
|
455
503
|
require 'celluloid/mailbox'
|
504
|
+
require 'celluloid/evented_mailbox'
|
456
505
|
require 'celluloid/method'
|
457
506
|
require 'celluloid/receivers'
|
458
507
|
require 'celluloid/registry'
|
@@ -465,9 +514,11 @@ require 'celluloid/thread_handle'
|
|
465
514
|
require 'celluloid/uuid'
|
466
515
|
|
467
516
|
require 'celluloid/proxies/abstract_proxy'
|
517
|
+
require 'celluloid/proxies/sync_proxy'
|
468
518
|
require 'celluloid/proxies/actor_proxy'
|
469
519
|
require 'celluloid/proxies/async_proxy'
|
470
520
|
require 'celluloid/proxies/future_proxy'
|
521
|
+
require 'celluloid/proxies/block_proxy'
|
471
522
|
|
472
523
|
require 'celluloid/actor'
|
473
524
|
require 'celluloid/future'
|
@@ -483,3 +534,4 @@ require 'celluloid/legacy' unless defined?(CELLULOID_FUTURE)
|
|
483
534
|
Celluloid.task_class = Celluloid::TaskFiber
|
484
535
|
Celluloid.logger = Logger.new(STDERR)
|
485
536
|
Celluloid.shutdown_timeout = 10
|
537
|
+
Celluloid.register_shutdown
|
data/lib/celluloid/actor.rb
CHANGED
@@ -10,7 +10,7 @@ module Celluloid
|
|
10
10
|
# A timeout occured before the given request could complete
|
11
11
|
class TimeoutError < StandardError; end
|
12
12
|
|
13
|
-
# The
|
13
|
+
# The sender made an error, not the current actor
|
14
14
|
class AbortError < StandardError
|
15
15
|
attr_reader :cause
|
16
16
|
|
@@ -27,7 +27,7 @@ module Celluloid
|
|
27
27
|
# normal Ruby objects wrapped in threads which communicate with asynchronous
|
28
28
|
# messages.
|
29
29
|
class Actor
|
30
|
-
attr_reader :subject, :proxy, :tasks, :links, :mailbox, :thread, :name
|
30
|
+
attr_reader :subject, :proxy, :tasks, :links, :mailbox, :thread, :name, :locals
|
31
31
|
|
32
32
|
class << self
|
33
33
|
extend Forwardable
|
@@ -58,42 +58,29 @@ module Celluloid
|
|
58
58
|
|
59
59
|
# Invoke a method on the given actor via its mailbox
|
60
60
|
def call(mailbox, meth, *args, &block)
|
61
|
-
|
62
|
-
|
63
|
-
begin
|
64
|
-
mailbox << call
|
65
|
-
rescue MailboxError
|
66
|
-
raise DeadActorError, "attempted to call a dead actor"
|
67
|
-
end
|
68
|
-
|
69
|
-
Celluloid.suspend(:callwait, call).value
|
61
|
+
proxy = SyncProxy.new(mailbox, "UnknownClass")
|
62
|
+
proxy.method_missing(meth, *args, &block)
|
70
63
|
end
|
71
64
|
|
72
65
|
# Invoke a method asynchronously on an actor via its mailbox
|
73
66
|
def async(mailbox, meth, *args, &block)
|
74
|
-
|
75
|
-
|
76
|
-
rescue MailboxError
|
77
|
-
# Silently swallow asynchronous calls to dead actors. There's no way
|
78
|
-
# to reliably generate DeadActorErrors for async calls, so users of
|
79
|
-
# async calls should find other ways to deal with actors dying
|
80
|
-
# during an async call (i.e. linking/supervisors)
|
81
|
-
end
|
67
|
+
proxy = AsyncProxy.new(mailbox, "UnknownClass")
|
68
|
+
proxy.method_missing(meth, *args, &block)
|
82
69
|
end
|
83
70
|
|
84
71
|
# Call a method asynchronously and retrieve its value later
|
85
72
|
def future(mailbox, meth, *args, &block)
|
86
|
-
|
87
|
-
|
88
|
-
future
|
73
|
+
proxy = FutureProxy.new(mailbox, "UnknownClass")
|
74
|
+
proxy.method_missing(meth, *args, &block)
|
89
75
|
end
|
90
76
|
|
91
77
|
# Obtain all running actors in the system
|
92
78
|
def all
|
93
79
|
actors = []
|
94
80
|
Thread.list.each do |t|
|
95
|
-
|
96
|
-
|
81
|
+
next unless t.celluloid?
|
82
|
+
next if t.task
|
83
|
+
actors << t.actor.proxy if t.actor && t.actor.respond_to?(:proxy)
|
97
84
|
end
|
98
85
|
actors
|
99
86
|
end
|
@@ -142,8 +129,8 @@ module Celluloid
|
|
142
129
|
end
|
143
130
|
|
144
131
|
# Wait for an actor to terminate
|
145
|
-
def join(actor)
|
146
|
-
actor.thread.join
|
132
|
+
def join(actor, timeout = nil)
|
133
|
+
actor.thread.join(timeout)
|
147
134
|
actor
|
148
135
|
end
|
149
136
|
end
|
@@ -154,6 +141,7 @@ module Celluloid
|
|
154
141
|
@mailbox = options[:mailbox] || Mailbox.new
|
155
142
|
@exit_handler = options[:exit_handler]
|
156
143
|
@exclusives = options[:exclusive_methods]
|
144
|
+
@receiver_block_executions = options[:receiver_block_executions]
|
157
145
|
@task_class = options[:task_class] || Celluloid.task_class
|
158
146
|
|
159
147
|
@tasks = TaskSet.new
|
@@ -164,10 +152,10 @@ module Celluloid
|
|
164
152
|
@running = true
|
165
153
|
@exclusive = false
|
166
154
|
@name = nil
|
155
|
+
@locals = {}
|
167
156
|
|
168
157
|
@thread = ThreadHandle.new do
|
169
|
-
|
170
|
-
Thread.current[:celluloid_mailbox] = @mailbox
|
158
|
+
setup_thread
|
171
159
|
run
|
172
160
|
end
|
173
161
|
|
@@ -175,6 +163,11 @@ module Celluloid
|
|
175
163
|
@subject.instance_variable_set(OWNER_IVAR, self)
|
176
164
|
end
|
177
165
|
|
166
|
+
def setup_thread
|
167
|
+
Thread.current[:celluloid_actor] = self
|
168
|
+
Thread.current[:celluloid_mailbox] = @mailbox
|
169
|
+
end
|
170
|
+
|
178
171
|
# Run the actor loop
|
179
172
|
def run
|
180
173
|
begin
|
@@ -323,8 +316,20 @@ module Celluloid
|
|
323
316
|
when SystemEvent
|
324
317
|
handle_system_event message
|
325
318
|
when Call
|
326
|
-
task(:
|
327
|
-
|
319
|
+
task(:call, message.method) {
|
320
|
+
if @receiver_block_executions && meth = message.method
|
321
|
+
if meth == :__send__
|
322
|
+
meth = message.arguments.first
|
323
|
+
end
|
324
|
+
if @receiver_block_executions.include?(meth.to_sym)
|
325
|
+
message.execute_block_on_receiver
|
326
|
+
end
|
327
|
+
end
|
328
|
+
message.dispatch(@subject)
|
329
|
+
}
|
330
|
+
when BlockCall
|
331
|
+
task(:invoke_block) { message.dispatch }
|
332
|
+
when BlockResponse, Response
|
328
333
|
message.dispatch
|
329
334
|
else
|
330
335
|
@receivers.handle_message(message)
|
data/lib/celluloid/autostart.rb
CHANGED
@@ -1,16 +1,3 @@
|
|
1
1
|
require 'celluloid'
|
2
2
|
|
3
3
|
Celluloid.boot
|
4
|
-
|
5
|
-
# Terminate all actors at exit
|
6
|
-
at_exit do
|
7
|
-
if defined?(RUBY_ENGINE) && RUBY_ENGINE == "ruby" && RUBY_VERSION >= "1.9"
|
8
|
-
# workaround for MRI bug losing exit status in at_exit block
|
9
|
-
# http://bugs.ruby-lang.org/issues/5218
|
10
|
-
exit_status = $!.status if $!.is_a?(SystemExit)
|
11
|
-
Celluloid.shutdown
|
12
|
-
exit exit_status if exit_status
|
13
|
-
else
|
14
|
-
Celluloid.shutdown
|
15
|
-
end
|
16
|
-
end
|
data/lib/celluloid/calls.rb
CHANGED
@@ -4,19 +4,33 @@ module Celluloid
|
|
4
4
|
attr_reader :method, :arguments, :block
|
5
5
|
|
6
6
|
def initialize(method, arguments = [], block = nil)
|
7
|
-
@method, @arguments
|
7
|
+
@method, @arguments = method, arguments
|
8
|
+
if block
|
9
|
+
if Celluloid.exclusive?
|
10
|
+
# FIXME: nicer exception
|
11
|
+
raise "Cannot execute blocks on sender in exclusive mode"
|
12
|
+
end
|
13
|
+
@block = BlockProxy.new(self, Celluloid.mailbox, block)
|
14
|
+
else
|
15
|
+
@block = nil
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def execute_block_on_receiver
|
20
|
+
@block && @block.execution = :receiver
|
8
21
|
end
|
9
22
|
|
10
23
|
def dispatch(obj)
|
11
|
-
|
24
|
+
_block = @block && @block.to_proc
|
25
|
+
obj.public_send(@method, *@arguments, &_block)
|
12
26
|
rescue NoMethodError => ex
|
13
|
-
# Abort if the
|
27
|
+
# Abort if the sender made a mistake
|
14
28
|
raise AbortError.new(ex) unless obj.respond_to? @method
|
15
29
|
|
16
30
|
# Otherwise something blew up. Crash this actor
|
17
31
|
raise
|
18
32
|
rescue ArgumentError => ex
|
19
|
-
# Abort if the
|
33
|
+
# Abort if the sender made a mistake
|
20
34
|
begin
|
21
35
|
arity = obj.method(@method).arity
|
22
36
|
rescue NameError
|
@@ -34,26 +48,16 @@ module Celluloid
|
|
34
48
|
# Otherwise something blew up. Crash this actor
|
35
49
|
raise
|
36
50
|
end
|
37
|
-
|
38
|
-
def wait
|
39
|
-
loop do
|
40
|
-
message = Thread.mailbox.receive do |msg|
|
41
|
-
msg.respond_to?(:call) and msg.call == self
|
42
|
-
end
|
43
|
-
break message unless message.is_a?(SystemEvent)
|
44
|
-
Thread.current[:celluloid_actor].handle_system_event(message)
|
45
|
-
end
|
46
|
-
end
|
47
51
|
end
|
48
52
|
|
49
53
|
# Synchronous calls wait for a response
|
50
54
|
class SyncCall < Call
|
51
|
-
attr_reader :
|
55
|
+
attr_reader :sender, :task, :chain_id
|
52
56
|
|
53
|
-
def initialize(
|
57
|
+
def initialize(sender, method, arguments = [], block = nil, task = Thread.current[:celluloid_task], chain_id = Thread.current[:celluloid_chain_id])
|
54
58
|
super(method, arguments, block)
|
55
59
|
|
56
|
-
@
|
60
|
+
@sender = sender
|
57
61
|
@task = task
|
58
62
|
@chain_id = chain_id || Celluloid.uuid
|
59
63
|
end
|
@@ -64,11 +68,11 @@ module Celluloid
|
|
64
68
|
respond SuccessResponse.new(self, result)
|
65
69
|
rescue Exception => ex
|
66
70
|
# Exceptions that occur during synchronous calls are reraised in the
|
67
|
-
# context of the
|
71
|
+
# context of the sender
|
68
72
|
respond ErrorResponse.new(self, ex)
|
69
73
|
|
70
|
-
# Aborting indicates a protocol error on the part of the
|
71
|
-
# It should crash the
|
74
|
+
# Aborting indicates a protocol error on the part of the sender
|
75
|
+
# It should crash the sender, but the exception isn't reraised
|
72
76
|
# Otherwise, it's a bug in this actor and should be reraised
|
73
77
|
raise unless ex.is_a?(AbortError)
|
74
78
|
ensure
|
@@ -81,11 +85,36 @@ module Celluloid
|
|
81
85
|
end
|
82
86
|
|
83
87
|
def respond(message)
|
84
|
-
@
|
88
|
+
@sender << message
|
85
89
|
rescue MailboxError
|
86
|
-
# It's possible the
|
90
|
+
# It's possible the sender exited or crashed before we could send a
|
87
91
|
# response to them.
|
88
92
|
end
|
93
|
+
|
94
|
+
def value
|
95
|
+
Celluloid.suspend(:callwait, self).value
|
96
|
+
end
|
97
|
+
|
98
|
+
def wait
|
99
|
+
loop do
|
100
|
+
message = Celluloid.mailbox.receive do |msg|
|
101
|
+
msg.respond_to?(:call) and msg.call == self
|
102
|
+
end
|
103
|
+
|
104
|
+
if message.is_a?(SystemEvent)
|
105
|
+
Thread.current[:celluloid_actor].handle_system_event(message)
|
106
|
+
else
|
107
|
+
# FIXME: add check for receiver block execution
|
108
|
+
if message.respond_to?(:value)
|
109
|
+
# FIXME: disable block execution if on :sender and (exclusive or outside of task)
|
110
|
+
# probably now in Call
|
111
|
+
break message
|
112
|
+
else
|
113
|
+
message.dispatch
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
89
118
|
end
|
90
119
|
|
91
120
|
# Asynchronous calls don't wait for a response
|
@@ -95,7 +124,7 @@ module Celluloid
|
|
95
124
|
Thread.current[:celluloid_chain_id] = Celluloid.uuid
|
96
125
|
super(obj)
|
97
126
|
rescue AbortError => ex
|
98
|
-
# Swallow aborted async calls, as they indicate the
|
127
|
+
# Swallow aborted async calls, as they indicate the sender made a mistake
|
99
128
|
Logger.debug("#{obj.class}: async call `#@method` aborted!\n#{Logger.format_exception(ex.cause)}")
|
100
129
|
ensure
|
101
130
|
Thread.current[:celluloid_chain_id] = nil
|
@@ -103,4 +132,23 @@ module Celluloid
|
|
103
132
|
|
104
133
|
end
|
105
134
|
|
135
|
+
class BlockCall
|
136
|
+
def initialize(block_proxy, sender, arguments, task = Thread.current[:celluloid_task])
|
137
|
+
@block_proxy = block_proxy
|
138
|
+
@sender = sender
|
139
|
+
@arguments = arguments
|
140
|
+
@task = task
|
141
|
+
end
|
142
|
+
attr_reader :task
|
143
|
+
|
144
|
+
def call
|
145
|
+
@block_proxy.call
|
146
|
+
end
|
147
|
+
|
148
|
+
def dispatch
|
149
|
+
response = @block_proxy.block.call(*@arguments)
|
150
|
+
@sender << BlockResponse.new(self, response)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
106
154
|
end
|