celluloid 0.15.2 → 0.16.0.pre2
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 +86 -133
- 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 +27 -18
- data/lib/celluloid/evented_mailbox.rb +8 -15
- 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 +0 -3
- data/lib/celluloid/logger.rb +30 -0
- data/lib/celluloid/logging/incident_logger.rb +1 -1
- data/lib/celluloid/mailbox.rb +19 -18
- 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 +3 -1
- data/lib/celluloid/registry.rb +1 -8
- 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 +6 -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/spec_helper.rb +20 -7
- data/spec/support/actor_examples.rb +33 -15
- data/spec/support/mailbox_examples.rb +9 -3
- data/spec/support/task_examples.rb +2 -0
- metadata +46 -22
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c9c58eede0a8ebeb315bf6f2fa925e19173dd5e9
|
|
4
|
+
data.tar.gz: 525f0ae4823a55ca1e23bf1ff5b6c8493592551f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2ac75588d4accd17305ea04b6329563783db6972262584898e3143bdf6086ba47dc8bcf8c93ad6c7a8b44115c2c718fbcc615219da968ffdfa8a7a5f17b5f908
|
|
7
|
+
data.tar.gz: e1185014388060dcd75a41b583a6df01f7bcbb37e21e1619091e364374cb861a31df7c7110b371887540c2482ff54cfae0cf7a3df534fc188157e220d5f8cd12
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2011-2014 Tony Arcieri
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
CHANGED
|
@@ -94,6 +94,28 @@ The following API documentation is also available:
|
|
|
94
94
|
* [Celluloid class methods](http://rubydoc.info/gems/celluloid/Celluloid/ClassMethods)
|
|
95
95
|
* [All Celluloid classes](http://rubydoc.info/gems/celluloid/index)
|
|
96
96
|
|
|
97
|
+
Related Projects
|
|
98
|
+
----------------
|
|
99
|
+
|
|
100
|
+
Celluloid is the parent project of a related ecosystem of other projects. If you
|
|
101
|
+
like Celluloid we definitely recommend you check them out:
|
|
102
|
+
|
|
103
|
+
* [Celluloid::IO][celluloid-io]: "Evented" IO support for Celluloid actors
|
|
104
|
+
* [Celluloid::ZMQ][celluloid-zmq]: "Evented" 0MQ support for Celluloid actors
|
|
105
|
+
* [DCell][dcell]: The Celluloid actor protocol distributed over 0MQ
|
|
106
|
+
* [Reel][reel]: An "evented" web server based on Celluloid::IO
|
|
107
|
+
* [Lattice][lattice]: A concurrent realtime web framework based on Celluloid::IO
|
|
108
|
+
* [nio4r][nio4r]: "New IO for Ruby": high performance IO selectors
|
|
109
|
+
* [Timers][timers]: A generic Ruby timer library for event-based systems
|
|
110
|
+
|
|
111
|
+
[celluloid-io]: https://github.com/celluloid/celluloid-io/
|
|
112
|
+
[celluloid-zmq]: https://github.com/celluloid/celluloid-zmq/
|
|
113
|
+
[dcell]: https://github.com/celluloid/dcell/
|
|
114
|
+
[reel]: https://github.com/celluloid/reel/
|
|
115
|
+
[lattice]: https://github.com/celluloid/lattice/
|
|
116
|
+
[nio4r]: https://github.com/celluloid/nio4r/
|
|
117
|
+
[timers]: https://github.com/celluloid/timers/
|
|
118
|
+
|
|
97
119
|
Installation
|
|
98
120
|
------------
|
|
99
121
|
|
|
@@ -131,7 +153,8 @@ Celluloid requires Ruby 1.9 mode on all interpreters.
|
|
|
131
153
|
Additional Reading
|
|
132
154
|
------------------
|
|
133
155
|
|
|
134
|
-
* [Concurrent Object-Oriented Programming in Python with
|
|
156
|
+
* [Concurrent Object-Oriented Programming in Python with
|
|
157
|
+
ATOM](http://citeseerx.ist.psu.edu/viewdoc/download;jsessionid=11A3EACE78AAFF6D6D62A64118AFCA7C?doi=10.1.1.47.5074&rep=rep1&type=pdf):
|
|
135
158
|
a similar system to Celluloid written in Python
|
|
136
159
|
|
|
137
160
|
Contributing to Celluloid
|
|
@@ -145,5 +168,5 @@ Contributing to Celluloid
|
|
|
145
168
|
License
|
|
146
169
|
-------
|
|
147
170
|
|
|
148
|
-
Copyright (c)
|
|
171
|
+
Copyright (c) 2011-2014 Tony Arcieri. Distributed under the MIT License. See
|
|
149
172
|
LICENSE.txt for further details.
|
data/lib/celluloid/actor.rb
CHANGED
|
@@ -1,56 +1,28 @@
|
|
|
1
|
+
|
|
1
2
|
require 'timers'
|
|
2
3
|
|
|
3
4
|
module Celluloid
|
|
4
|
-
# Don't do Actor-like things outside Actor scope
|
|
5
|
-
class NotActorError < Celluloid::Error; end
|
|
6
|
-
|
|
7
|
-
# Trying to do something to a dead actor
|
|
8
|
-
class DeadActorError < Celluloid::Error; end
|
|
9
|
-
|
|
10
|
-
# A timeout occured before the given request could complete
|
|
11
|
-
class TimeoutError < Celluloid::Error; end
|
|
12
|
-
|
|
13
|
-
# The sender made an error, not the current actor
|
|
14
|
-
class AbortError < Celluloid::Error
|
|
15
|
-
attr_reader :cause
|
|
16
|
-
|
|
17
|
-
def initialize(cause)
|
|
18
|
-
@cause = cause
|
|
19
|
-
super "caused by #{cause.inspect}: #{cause.to_s}"
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
LINKING_TIMEOUT = 5 # linking times out after 5 seconds
|
|
24
|
-
OWNER_IVAR = :@celluloid_owner # reference to owning actor
|
|
25
|
-
|
|
26
5
|
# Actors are Celluloid's concurrency primitive. They're implemented as
|
|
27
6
|
# normal Ruby objects wrapped in threads which communicate with asynchronous
|
|
28
7
|
# messages.
|
|
29
8
|
class Actor
|
|
30
|
-
attr_reader :
|
|
9
|
+
attr_reader :behavior, :proxy, :tasks, :links, :mailbox, :thread, :name, :timers
|
|
10
|
+
attr_writer :exit_handler
|
|
31
11
|
|
|
32
12
|
class << self
|
|
33
13
|
extend Forwardable
|
|
34
14
|
|
|
35
|
-
def_delegators "Celluloid
|
|
36
|
-
|
|
37
|
-
def registered
|
|
38
|
-
Registry.root.names
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
def clear_registry
|
|
42
|
-
Registry.root.clear
|
|
43
|
-
end
|
|
15
|
+
def_delegators "Celluloid.actor_system", :[], :[]=, :delete, :registered, :clear_registry
|
|
44
16
|
|
|
45
17
|
# Obtain the current actor
|
|
46
18
|
def current
|
|
47
19
|
actor = Thread.current[:celluloid_actor]
|
|
48
20
|
raise NotActorError, "not in actor scope" unless actor
|
|
49
|
-
actor.
|
|
21
|
+
actor.behavior_proxy
|
|
50
22
|
end
|
|
51
23
|
|
|
52
24
|
# Obtain the name of the current actor
|
|
53
|
-
def
|
|
25
|
+
def registered_name
|
|
54
26
|
actor = Thread.current[:celluloid_actor]
|
|
55
27
|
raise NotActorError, "not in actor scope" unless actor
|
|
56
28
|
actor.name
|
|
@@ -76,12 +48,7 @@ module Celluloid
|
|
|
76
48
|
|
|
77
49
|
# Obtain all running actors in the system
|
|
78
50
|
def all
|
|
79
|
-
|
|
80
|
-
Celluloid.internal_pool.each do |t|
|
|
81
|
-
next unless t.role == :actor
|
|
82
|
-
actors << t.actor.proxy if t.actor && t.actor.respond_to?(:proxy)
|
|
83
|
-
end
|
|
84
|
-
actors
|
|
51
|
+
Celluloid.actor_system.running
|
|
85
52
|
end
|
|
86
53
|
|
|
87
54
|
# Watch for exit events from another actor
|
|
@@ -131,34 +98,44 @@ module Celluloid
|
|
|
131
98
|
end
|
|
132
99
|
end
|
|
133
100
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
@subject = subject
|
|
101
|
+
def initialize(behavior, options)
|
|
102
|
+
@behavior = behavior
|
|
137
103
|
|
|
104
|
+
@actor_system = options.fetch(:actor_system)
|
|
138
105
|
@mailbox = options.fetch(:mailbox_class, Mailbox).new
|
|
139
106
|
@mailbox.max_size = options.fetch(:mailbox_size, nil)
|
|
140
107
|
|
|
141
108
|
@task_class = options[:task_class] || Celluloid.task_class
|
|
142
|
-
@exit_handler =
|
|
143
|
-
@
|
|
144
|
-
@receiver_block_executions = options[:receiver_block_executions]
|
|
109
|
+
@exit_handler = method(:default_exit_handler)
|
|
110
|
+
@exclusive = options.fetch(:exclusive, false)
|
|
145
111
|
|
|
146
112
|
@tasks = TaskSet.new
|
|
147
113
|
@links = Links.new
|
|
148
114
|
@signals = Signals.new
|
|
149
115
|
@receivers = Receivers.new
|
|
150
|
-
@timers = Timers.new
|
|
151
|
-
@
|
|
152
|
-
@
|
|
116
|
+
@timers = Timers::Group.new
|
|
117
|
+
@handlers = Handlers.new
|
|
118
|
+
@running = false
|
|
153
119
|
@name = nil
|
|
154
120
|
|
|
155
|
-
|
|
121
|
+
handle(SystemEvent) do |message|
|
|
122
|
+
handle_system_event message
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def start
|
|
127
|
+
@running = true
|
|
128
|
+
@thread = ThreadHandle.new(@actor_system, :actor) do
|
|
156
129
|
setup_thread
|
|
157
130
|
run
|
|
158
131
|
end
|
|
159
132
|
|
|
160
|
-
@proxy =
|
|
161
|
-
|
|
133
|
+
@proxy = ActorProxy.new(@thread, @mailbox)
|
|
134
|
+
Celluloid::Probe.actor_created(self) if $CELLULOID_MONITORING
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def behavior_proxy
|
|
138
|
+
@behavior.proxy
|
|
162
139
|
end
|
|
163
140
|
|
|
164
141
|
def setup_thread
|
|
@@ -168,18 +145,16 @@ module Celluloid
|
|
|
168
145
|
|
|
169
146
|
# Run the actor loop
|
|
170
147
|
def run
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
148
|
+
while @running
|
|
149
|
+
begin
|
|
150
|
+
message = @mailbox.receive(timeout_interval)
|
|
151
|
+
handle_message message
|
|
152
|
+
rescue TimeoutError
|
|
153
|
+
@timers.fire
|
|
154
|
+
@receivers.fire_timers
|
|
155
|
+
rescue MailboxShutdown
|
|
156
|
+
@running = false
|
|
180
157
|
end
|
|
181
|
-
rescue MailboxShutdown
|
|
182
|
-
# If the mailbox detects shutdown, exit the actor
|
|
183
158
|
end
|
|
184
159
|
|
|
185
160
|
shutdown
|
|
@@ -196,31 +171,37 @@ module Celluloid
|
|
|
196
171
|
# Perform a linking request with another actor
|
|
197
172
|
def linking_request(receiver, type)
|
|
198
173
|
Celluloid.exclusive do
|
|
199
|
-
|
|
174
|
+
linking_timeout = Timers::Timeout.new(LINKING_TIMEOUT)
|
|
175
|
+
|
|
200
176
|
receiver.mailbox << LinkingRequest.new(Actor.current, type)
|
|
201
177
|
system_events = []
|
|
202
178
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
179
|
+
linking_timeout.while_time_remaining do |remaining|
|
|
180
|
+
begin
|
|
181
|
+
message = @mailbox.receive(remaining) do |msg|
|
|
182
|
+
msg.is_a?(LinkingResponse) &&
|
|
183
|
+
msg.actor.mailbox.address == receiver.mailbox.address &&
|
|
184
|
+
msg.type == type
|
|
185
|
+
end
|
|
186
|
+
rescue TimeoutError
|
|
187
|
+
next # IO reactor did something, no message in queue yet.
|
|
209
188
|
end
|
|
210
189
|
|
|
211
|
-
|
|
212
|
-
|
|
190
|
+
if message.instance_of? LinkingResponse
|
|
191
|
+
Celluloid::Probe.actors_linked(self, receiver) if $CELLULOID_MONITORING
|
|
192
|
+
|
|
213
193
|
# We're done!
|
|
214
|
-
system_events.each { |ev|
|
|
194
|
+
system_events.each { |ev| @mailbox << ev }
|
|
195
|
+
|
|
215
196
|
return
|
|
216
|
-
|
|
217
|
-
raise TimeoutError, "linking timeout of #{LINKING_TIMEOUT} seconds exceeded"
|
|
218
|
-
when SystemEvent
|
|
197
|
+
elsif message.is_a? SystemEvent
|
|
219
198
|
# Queue up pending system events to be processed after we've successfully linked
|
|
220
199
|
system_events << message
|
|
221
|
-
else raise
|
|
200
|
+
else raise "Unexpected message type: #{message.class}. Expected LinkingResponse, NilClass, SystemEvent."
|
|
222
201
|
end
|
|
223
202
|
end
|
|
203
|
+
|
|
204
|
+
raise TimeoutError, "linking timeout of #{LINKING_TIMEOUT} seconds exceeded"
|
|
224
205
|
end
|
|
225
206
|
end
|
|
226
207
|
|
|
@@ -234,6 +215,10 @@ module Celluloid
|
|
|
234
215
|
@signals.wait name
|
|
235
216
|
end
|
|
236
217
|
|
|
218
|
+
def handle(*patterns, &block)
|
|
219
|
+
@handlers.handle(*patterns, &block)
|
|
220
|
+
end
|
|
221
|
+
|
|
237
222
|
# Receive an asynchronous message
|
|
238
223
|
def receive(timeout = nil, &block)
|
|
239
224
|
loop do
|
|
@@ -304,28 +289,7 @@ module Celluloid
|
|
|
304
289
|
|
|
305
290
|
# Handle standard low-priority messages
|
|
306
291
|
def handle_message(message)
|
|
307
|
-
|
|
308
|
-
when SystemEvent
|
|
309
|
-
handle_system_event message
|
|
310
|
-
when Call
|
|
311
|
-
meth = message.method
|
|
312
|
-
if meth == :__send__
|
|
313
|
-
meth = message.arguments.first
|
|
314
|
-
end
|
|
315
|
-
if @receiver_block_executions && meth
|
|
316
|
-
if @receiver_block_executions.include?(meth.to_sym)
|
|
317
|
-
message.execute_block_on_receiver
|
|
318
|
-
end
|
|
319
|
-
end
|
|
320
|
-
|
|
321
|
-
task(:call, :method_name => meth, :dangerous_suspend => meth == :initialize) {
|
|
322
|
-
message.dispatch(@subject)
|
|
323
|
-
}
|
|
324
|
-
when BlockCall
|
|
325
|
-
task(:invoke_block) { message.dispatch }
|
|
326
|
-
when BlockResponse, Response
|
|
327
|
-
message.dispatch
|
|
328
|
-
else
|
|
292
|
+
unless @handlers.handle_message(message)
|
|
329
293
|
unless @receivers.handle_message(message)
|
|
330
294
|
Logger.debug "Discarded message (unhandled): #{message}" if $CELLULOID_DEBUG
|
|
331
295
|
end
|
|
@@ -335,17 +299,19 @@ module Celluloid
|
|
|
335
299
|
|
|
336
300
|
# Handle high-priority system event messages
|
|
337
301
|
def handle_system_event(event)
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
when LinkingRequest
|
|
302
|
+
if event.instance_of? ExitEvent
|
|
303
|
+
handle_exit_event(event)
|
|
304
|
+
elsif event.instance_of? LinkingRequest
|
|
342
305
|
event.process(links)
|
|
343
|
-
|
|
306
|
+
elsif event.instance_of? NamingRequest
|
|
344
307
|
@name = event.name
|
|
345
|
-
|
|
308
|
+
Celluloid::Probe.actor_named(self) if $CELLULOID_MONITORING
|
|
309
|
+
elsif event.instance_of? TerminationRequest
|
|
346
310
|
terminate
|
|
347
|
-
|
|
311
|
+
elsif event.instance_of? SignalConditionRequest
|
|
348
312
|
event.call
|
|
313
|
+
else
|
|
314
|
+
Logger.debug "Discarded message (unhandled): #{message}" if $CELLULOID_DEBUG
|
|
349
315
|
end
|
|
350
316
|
end
|
|
351
317
|
|
|
@@ -353,47 +319,34 @@ module Celluloid
|
|
|
353
319
|
def handle_exit_event(event)
|
|
354
320
|
@links.delete event.actor
|
|
355
321
|
|
|
356
|
-
|
|
357
|
-
|
|
322
|
+
@exit_handler.call(event)
|
|
323
|
+
end
|
|
358
324
|
|
|
359
|
-
|
|
360
|
-
# If no reason is given, actor terminated cleanly
|
|
325
|
+
def default_exit_handler(event)
|
|
361
326
|
raise event.reason if event.reason
|
|
362
327
|
end
|
|
363
328
|
|
|
364
329
|
# Handle any exceptions that occur within a running actor
|
|
365
330
|
def handle_crash(exception)
|
|
366
|
-
|
|
367
|
-
|
|
331
|
+
# TODO: add meta info
|
|
332
|
+
Logger.crash("Actor crashed!", exception)
|
|
333
|
+
shutdown ExitEvent.new(behavior_proxy, exception)
|
|
368
334
|
rescue => ex
|
|
369
|
-
Logger.crash("
|
|
335
|
+
Logger.crash("ERROR HANDLER CRASHED!", ex)
|
|
370
336
|
end
|
|
371
337
|
|
|
372
338
|
# Handle cleaning up this actor after it exits
|
|
373
|
-
def shutdown(exit_event = ExitEvent.new(
|
|
374
|
-
|
|
339
|
+
def shutdown(exit_event = ExitEvent.new(behavior_proxy))
|
|
340
|
+
@behavior.shutdown
|
|
375
341
|
cleanup exit_event
|
|
376
342
|
ensure
|
|
377
343
|
Thread.current[:celluloid_actor] = nil
|
|
378
344
|
Thread.current[:celluloid_mailbox] = nil
|
|
379
345
|
end
|
|
380
346
|
|
|
381
|
-
# Run the user-defined finalizer, if one is set
|
|
382
|
-
def run_finalizer
|
|
383
|
-
finalizer = @subject.class.finalizer
|
|
384
|
-
return unless finalizer && @subject.respond_to?(finalizer, true)
|
|
385
|
-
|
|
386
|
-
task(:finalizer, :method_name => finalizer, :dangerous_suspend => true) do
|
|
387
|
-
begin
|
|
388
|
-
@subject.__send__(finalizer)
|
|
389
|
-
rescue => ex
|
|
390
|
-
Logger.crash("#{@subject.class}#finalize crashed!", ex)
|
|
391
|
-
end
|
|
392
|
-
end
|
|
393
|
-
end
|
|
394
|
-
|
|
395
347
|
# Clean up after this actor
|
|
396
348
|
def cleanup(exit_event)
|
|
349
|
+
Celluloid::Probe.actor_died(self) if $CELLULOID_MONITORING
|
|
397
350
|
@mailbox.shutdown
|
|
398
351
|
@links.each do |actor|
|
|
399
352
|
if actor.mailbox.alive?
|
|
@@ -401,16 +354,16 @@ module Celluloid
|
|
|
401
354
|
end
|
|
402
355
|
end
|
|
403
356
|
|
|
404
|
-
tasks.to_a.each
|
|
357
|
+
tasks.to_a.each(&:terminate)
|
|
405
358
|
rescue => ex
|
|
406
|
-
|
|
359
|
+
# TODO: metadata
|
|
360
|
+
Logger.crash("CLEANUP CRASHED!", ex)
|
|
407
361
|
end
|
|
408
362
|
|
|
409
363
|
# Run a method inside a task unless it's exclusive
|
|
410
364
|
def task(task_type, meta = nil)
|
|
411
|
-
method_name = meta && meta.fetch(:method_name, nil)
|
|
412
365
|
@task_class.new(task_type, meta) {
|
|
413
|
-
if @
|
|
366
|
+
if @exclusive
|
|
414
367
|
Celluloid.exclusive { yield }
|
|
415
368
|
else
|
|
416
369
|
yield
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
module Celluloid
|
|
2
|
+
class ActorSystem
|
|
3
|
+
extend Forwardable
|
|
4
|
+
|
|
5
|
+
def initialize
|
|
6
|
+
@internal_pool = InternalPool.new
|
|
7
|
+
@registry = Registry.new
|
|
8
|
+
end
|
|
9
|
+
attr_reader :registry
|
|
10
|
+
|
|
11
|
+
# Launch default services
|
|
12
|
+
# FIXME: We should set up the supervision hierarchy here
|
|
13
|
+
def start
|
|
14
|
+
within do
|
|
15
|
+
Celluloid::Notifications::Fanout.supervise_as :notifications_fanout
|
|
16
|
+
Celluloid::IncidentReporter.supervise_as :default_incident_reporter, STDERR
|
|
17
|
+
end
|
|
18
|
+
true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def within
|
|
22
|
+
old = Thread.current[:celluloid_actor_system]
|
|
23
|
+
Thread.current[:celluloid_actor_system] = self
|
|
24
|
+
yield
|
|
25
|
+
ensure
|
|
26
|
+
Thread.current[:celluloid_actor_system] = old
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def get_thread
|
|
30
|
+
@internal_pool.get do
|
|
31
|
+
Thread.current[:celluloid_actor_system] = self
|
|
32
|
+
yield
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def stack_dump
|
|
37
|
+
Celluloid::StackDump.new(@internal_pool)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def_delegators "@registry", :[], :get, :[]=, :set, :delete
|
|
41
|
+
|
|
42
|
+
def registered
|
|
43
|
+
@registry.names
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def clear_registry
|
|
47
|
+
@registry.clear
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def running
|
|
51
|
+
actors = []
|
|
52
|
+
@internal_pool.each do |t|
|
|
53
|
+
next unless t.role == :actor
|
|
54
|
+
actors << t.actor.behavior_proxy if t.actor && t.actor.respond_to?(:behavior_proxy)
|
|
55
|
+
end
|
|
56
|
+
actors
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def running?
|
|
60
|
+
@internal_pool.running?
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# Shut down all running actors
|
|
64
|
+
def shutdown
|
|
65
|
+
actors = running
|
|
66
|
+
Timeout.timeout(shutdown_timeout) do
|
|
67
|
+
Logger.debug "Terminating #{actors.size} #{(actors.size > 1) ? 'actors' : 'actor'}..." if actors.size > 0
|
|
68
|
+
|
|
69
|
+
# Actors cannot self-terminate, you must do it for them
|
|
70
|
+
actors.each do |actor|
|
|
71
|
+
begin
|
|
72
|
+
actor.terminate!
|
|
73
|
+
rescue DeadActorError
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
actors.each do |actor|
|
|
78
|
+
begin
|
|
79
|
+
Actor.join(actor)
|
|
80
|
+
rescue DeadActorError
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
@internal_pool.shutdown
|
|
85
|
+
end
|
|
86
|
+
rescue Timeout::Error
|
|
87
|
+
Logger.error("Couldn't cleanly terminate all actors in #{shutdown_timeout} seconds!")
|
|
88
|
+
actors.each do |actor|
|
|
89
|
+
begin
|
|
90
|
+
Actor.kill(actor)
|
|
91
|
+
rescue DeadActorError, MailboxDead
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
ensure
|
|
95
|
+
@internal_pool.kill
|
|
96
|
+
clear_registry
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def assert_inactive
|
|
100
|
+
@internal_pool.assert_inactive
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def shutdown_timeout
|
|
104
|
+
Celluloid.shutdown_timeout
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
data/lib/celluloid/call_chain.rb
CHANGED
data/lib/celluloid/calls.rb
CHANGED
|
@@ -21,32 +21,28 @@ module Celluloid
|
|
|
21
21
|
end
|
|
22
22
|
|
|
23
23
|
def dispatch(obj)
|
|
24
|
+
check(obj)
|
|
24
25
|
_block = @block && @block.to_proc
|
|
25
26
|
obj.public_send(@method, *@arguments, &_block)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
raise
|
|
32
|
-
rescue ArgumentError => ex
|
|
33
|
-
# Abort if the sender made a mistake
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def check(obj)
|
|
30
|
+
raise NoMethodError, "undefined method `#{@method}' for #{obj.inspect}" unless obj.respond_to? @method
|
|
31
|
+
|
|
34
32
|
begin
|
|
35
33
|
arity = obj.method(@method).arity
|
|
36
34
|
rescue NameError
|
|
37
|
-
|
|
38
|
-
raise AbortError.new(ex)
|
|
35
|
+
return
|
|
39
36
|
end
|
|
40
37
|
|
|
41
38
|
if arity >= 0
|
|
42
|
-
raise
|
|
39
|
+
raise ArgumentError, "wrong number of arguments (#{@arguments.size} for #{arity})" if @arguments.size != arity
|
|
43
40
|
elsif arity < -1
|
|
44
41
|
mandatory_args = -arity - 1
|
|
45
|
-
raise
|
|
42
|
+
raise ArgumentError, "wrong number of arguments (#{@arguments.size} for #{mandatory_args}+)" if arguments.size < mandatory_args
|
|
46
43
|
end
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
raise
|
|
44
|
+
rescue => ex
|
|
45
|
+
raise AbortError.new(ex)
|
|
50
46
|
end
|
|
51
47
|
end
|
|
52
48
|
|
|
@@ -88,8 +84,12 @@ module Celluloid
|
|
|
88
84
|
@sender << message
|
|
89
85
|
end
|
|
90
86
|
|
|
87
|
+
def response
|
|
88
|
+
Celluloid.suspend(:callwait, self)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
91
|
def value
|
|
92
|
-
|
|
92
|
+
response.value
|
|
93
93
|
end
|
|
94
94
|
|
|
95
95
|
def wait
|