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
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6b9e9584ba72b44bbb2ce23372b0b4b86f2f3687
|
|
4
|
+
data.tar.gz: 10ec35b6465a1025defe4a697c3108f1982b5f77
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9394c33b6d7eff1efa0e0f78d24ff5578ce208dac695d0b7b806c999b47a456253c670783599ae448cb9bb3f6bf455be4ac66705fb399d8e53c3adb72a894250
|
|
7
|
+
data.tar.gz: f3e2659328cb38517ec107ad32e7c08d8aaa40fece3d74213273d50f703a6cb0878a43616d933b41fb6d061d928f02ba68850d269be32107062bc5e7b162bcc2
|
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
|
-
@
|
|
150
|
-
@
|
|
151
|
-
@
|
|
152
|
-
@
|
|
115
|
+
@timers = Timers::Group.new
|
|
116
|
+
@receivers = Receivers.new(@timers)
|
|
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,20 @@ module Celluloid
|
|
|
168
145
|
|
|
169
146
|
# Run the actor loop
|
|
170
147
|
def run
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
148
|
+
while @running
|
|
149
|
+
begin
|
|
150
|
+
@timers.wait do |interval|
|
|
151
|
+
interval = 0 if interval and interval < 0
|
|
152
|
+
|
|
153
|
+
if message = @mailbox.check(interval)
|
|
154
|
+
handle_message(message)
|
|
155
|
+
|
|
156
|
+
break unless @running
|
|
157
|
+
end
|
|
179
158
|
end
|
|
159
|
+
rescue MailboxShutdown
|
|
160
|
+
@running = false
|
|
180
161
|
end
|
|
181
|
-
rescue MailboxShutdown
|
|
182
|
-
# If the mailbox detects shutdown, exit the actor
|
|
183
162
|
end
|
|
184
163
|
|
|
185
164
|
shutdown
|
|
@@ -196,31 +175,35 @@ module Celluloid
|
|
|
196
175
|
# Perform a linking request with another actor
|
|
197
176
|
def linking_request(receiver, type)
|
|
198
177
|
Celluloid.exclusive do
|
|
199
|
-
start_time = Time.now
|
|
200
178
|
receiver.mailbox << LinkingRequest.new(Actor.current, type)
|
|
201
179
|
system_events = []
|
|
202
180
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
181
|
+
Timers::Wait.for(LINKING_TIMEOUT) do |remaining|
|
|
182
|
+
begin
|
|
183
|
+
message = @mailbox.receive(remaining) do |msg|
|
|
184
|
+
msg.is_a?(LinkingResponse) &&
|
|
185
|
+
msg.actor.mailbox.address == receiver.mailbox.address &&
|
|
186
|
+
msg.type == type
|
|
187
|
+
end
|
|
188
|
+
rescue TimeoutError
|
|
189
|
+
next # IO reactor did something, no message in queue yet.
|
|
209
190
|
end
|
|
210
191
|
|
|
211
|
-
|
|
212
|
-
|
|
192
|
+
if message.instance_of? LinkingResponse
|
|
193
|
+
Celluloid::Probe.actors_linked(self, receiver) if $CELLULOID_MONITORING
|
|
194
|
+
|
|
213
195
|
# We're done!
|
|
214
|
-
system_events.each { |ev|
|
|
196
|
+
system_events.each { |ev| @mailbox << ev }
|
|
197
|
+
|
|
215
198
|
return
|
|
216
|
-
|
|
217
|
-
raise TimeoutError, "linking timeout of #{LINKING_TIMEOUT} seconds exceeded"
|
|
218
|
-
when SystemEvent
|
|
199
|
+
elsif message.is_a? SystemEvent
|
|
219
200
|
# Queue up pending system events to be processed after we've successfully linked
|
|
220
201
|
system_events << message
|
|
221
|
-
else raise
|
|
202
|
+
else raise "Unexpected message type: #{message.class}. Expected LinkingResponse, NilClass, SystemEvent."
|
|
222
203
|
end
|
|
223
204
|
end
|
|
205
|
+
|
|
206
|
+
raise TimeoutError, "linking timeout of #{LINKING_TIMEOUT} seconds exceeded"
|
|
224
207
|
end
|
|
225
208
|
end
|
|
226
209
|
|
|
@@ -234,6 +217,10 @@ module Celluloid
|
|
|
234
217
|
@signals.wait name
|
|
235
218
|
end
|
|
236
219
|
|
|
220
|
+
def handle(*patterns, &block)
|
|
221
|
+
@handlers.handle(*patterns, &block)
|
|
222
|
+
end
|
|
223
|
+
|
|
237
224
|
# Receive an asynchronous message
|
|
238
225
|
def receive(timeout = nil, &block)
|
|
239
226
|
loop do
|
|
@@ -244,20 +231,6 @@ module Celluloid
|
|
|
244
231
|
end
|
|
245
232
|
end
|
|
246
233
|
|
|
247
|
-
# How long to wait until the next timer fires
|
|
248
|
-
def timeout_interval
|
|
249
|
-
i1 = @timers.wait_interval
|
|
250
|
-
i2 = @receivers.wait_interval
|
|
251
|
-
|
|
252
|
-
if i1 and i2
|
|
253
|
-
i1 < i2 ? i1 : i2
|
|
254
|
-
elsif i1
|
|
255
|
-
i1
|
|
256
|
-
else
|
|
257
|
-
i2
|
|
258
|
-
end
|
|
259
|
-
end
|
|
260
|
-
|
|
261
234
|
# Schedule a block to run at the given time
|
|
262
235
|
def after(interval, &block)
|
|
263
236
|
@timers.after(interval) { task(:timer, &block) }
|
|
@@ -304,28 +277,7 @@ module Celluloid
|
|
|
304
277
|
|
|
305
278
|
# Handle standard low-priority messages
|
|
306
279
|
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
|
|
280
|
+
unless @handlers.handle_message(message)
|
|
329
281
|
unless @receivers.handle_message(message)
|
|
330
282
|
Logger.debug "Discarded message (unhandled): #{message}" if $CELLULOID_DEBUG
|
|
331
283
|
end
|
|
@@ -335,17 +287,19 @@ module Celluloid
|
|
|
335
287
|
|
|
336
288
|
# Handle high-priority system event messages
|
|
337
289
|
def handle_system_event(event)
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
when LinkingRequest
|
|
290
|
+
if event.instance_of? ExitEvent
|
|
291
|
+
handle_exit_event(event)
|
|
292
|
+
elsif event.instance_of? LinkingRequest
|
|
342
293
|
event.process(links)
|
|
343
|
-
|
|
294
|
+
elsif event.instance_of? NamingRequest
|
|
344
295
|
@name = event.name
|
|
345
|
-
|
|
296
|
+
Celluloid::Probe.actor_named(self) if $CELLULOID_MONITORING
|
|
297
|
+
elsif event.instance_of? TerminationRequest
|
|
346
298
|
terminate
|
|
347
|
-
|
|
299
|
+
elsif event.instance_of? SignalConditionRequest
|
|
348
300
|
event.call
|
|
301
|
+
else
|
|
302
|
+
Logger.debug "Discarded message (unhandled): #{message}" if $CELLULOID_DEBUG
|
|
349
303
|
end
|
|
350
304
|
end
|
|
351
305
|
|
|
@@ -353,47 +307,34 @@ module Celluloid
|
|
|
353
307
|
def handle_exit_event(event)
|
|
354
308
|
@links.delete event.actor
|
|
355
309
|
|
|
356
|
-
|
|
357
|
-
|
|
310
|
+
@exit_handler.call(event)
|
|
311
|
+
end
|
|
358
312
|
|
|
359
|
-
|
|
360
|
-
# If no reason is given, actor terminated cleanly
|
|
313
|
+
def default_exit_handler(event)
|
|
361
314
|
raise event.reason if event.reason
|
|
362
315
|
end
|
|
363
316
|
|
|
364
317
|
# Handle any exceptions that occur within a running actor
|
|
365
318
|
def handle_crash(exception)
|
|
366
|
-
|
|
367
|
-
|
|
319
|
+
# TODO: add meta info
|
|
320
|
+
Logger.crash("Actor crashed!", exception)
|
|
321
|
+
shutdown ExitEvent.new(behavior_proxy, exception)
|
|
368
322
|
rescue => ex
|
|
369
|
-
Logger.crash("
|
|
323
|
+
Logger.crash("ERROR HANDLER CRASHED!", ex)
|
|
370
324
|
end
|
|
371
325
|
|
|
372
326
|
# Handle cleaning up this actor after it exits
|
|
373
|
-
def shutdown(exit_event = ExitEvent.new(
|
|
374
|
-
|
|
327
|
+
def shutdown(exit_event = ExitEvent.new(behavior_proxy))
|
|
328
|
+
@behavior.shutdown
|
|
375
329
|
cleanup exit_event
|
|
376
330
|
ensure
|
|
377
331
|
Thread.current[:celluloid_actor] = nil
|
|
378
332
|
Thread.current[:celluloid_mailbox] = nil
|
|
379
333
|
end
|
|
380
334
|
|
|
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
335
|
# Clean up after this actor
|
|
396
336
|
def cleanup(exit_event)
|
|
337
|
+
Celluloid::Probe.actor_died(self) if $CELLULOID_MONITORING
|
|
397
338
|
@mailbox.shutdown
|
|
398
339
|
@links.each do |actor|
|
|
399
340
|
if actor.mailbox.alive?
|
|
@@ -401,16 +342,16 @@ module Celluloid
|
|
|
401
342
|
end
|
|
402
343
|
end
|
|
403
344
|
|
|
404
|
-
tasks.to_a.each
|
|
345
|
+
tasks.to_a.each(&:terminate)
|
|
405
346
|
rescue => ex
|
|
406
|
-
|
|
347
|
+
# TODO: metadata
|
|
348
|
+
Logger.crash("CLEANUP CRASHED!", ex)
|
|
407
349
|
end
|
|
408
350
|
|
|
409
351
|
# Run a method inside a task unless it's exclusive
|
|
410
352
|
def task(task_type, meta = nil)
|
|
411
|
-
method_name = meta && meta.fetch(:method_name, nil)
|
|
412
353
|
@task_class.new(task_type, meta) {
|
|
413
|
-
if @
|
|
354
|
+
if @exclusive
|
|
414
355
|
Celluloid.exclusive { yield }
|
|
415
356
|
else
|
|
416
357
|
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
|