celluloid 0.13.0 → 0.14.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Gem Version](https://badge.fury.io/rb/celluloid.png)](http://rubygems.org/gems/celluloid)
|
4
4
|
[![Build Status](https://secure.travis-ci.org/celluloid/celluloid.png?branch=master)](http://travis-ci.org/celluloid/celluloid)
|
5
|
-
[![Dependency Status](https://gemnasium.com/celluloid/celluloid.png)](https://gemnasium.com/celluloid/celluloid)
|
6
5
|
[![Code Climate](https://codeclimate.com/github/celluloid/celluloid.png)](https://codeclimate.com/github/celluloid/celluloid)
|
7
6
|
[![Coverage Status](https://coveralls.io/repos/celluloid/celluloid/badge.png?branch=master)](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
|