celluloid 0.16.0 → 0.17.3
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/CHANGES.md +394 -0
- data/LICENSE.txt +1 -1
- data/README.md +28 -15
- data/culture/CONDUCT.md +28 -0
- data/culture/Gemfile +9 -0
- data/culture/LICENSE.txt +22 -0
- data/culture/README.md +22 -0
- data/culture/Rakefile +5 -0
- data/culture/SYNC.md +70 -0
- data/culture/celluloid-culture.gemspec +18 -0
- data/culture/gems/README.md +39 -0
- data/culture/gems/dependencies.yml +85 -0
- data/culture/gems/loader.rb +101 -0
- data/culture/rubocop/README.md +38 -0
- data/culture/rubocop/lint.yml +8 -0
- data/culture/rubocop/metrics.yml +15 -0
- data/culture/rubocop/perf.yml +0 -0
- data/culture/rubocop/rubocop.yml +5 -0
- data/culture/rubocop/style.yml +57 -0
- data/culture/spec/gems_spec.rb +2 -0
- data/culture/spec/spec_helper.rb +0 -0
- data/culture/spec/sync_spec.rb +2 -0
- data/culture/sync.rb +56 -0
- data/culture/tasks/rspec.rake +5 -0
- data/culture/tasks/rubocop.rake +2 -0
- data/examples/basic_usage.rb +49 -0
- data/examples/futures.rb +38 -0
- data/examples/ring.rb +61 -0
- data/examples/simple_pmap.rb +14 -0
- data/examples/stack.rb +47 -0
- data/examples/timers.rb +72 -0
- data/lib/celluloid/actor/manager.rb +7 -0
- data/lib/celluloid/actor/system.rb +163 -0
- data/lib/celluloid/actor.rb +53 -71
- data/lib/celluloid/autostart.rb +1 -1
- data/lib/celluloid/backported.rb +2 -0
- data/lib/celluloid/call/async.rb +16 -0
- data/lib/celluloid/call/block.rb +22 -0
- data/lib/celluloid/call/sync.rb +70 -0
- data/lib/celluloid/calls.rb +24 -114
- data/lib/celluloid/cell.rb +32 -20
- data/lib/celluloid/condition.rb +5 -6
- data/lib/celluloid/core_ext.rb +1 -1
- data/lib/celluloid/current.rb +2 -0
- data/lib/celluloid/debug.rb +1 -0
- data/lib/celluloid/deprecate.rb +21 -0
- data/lib/celluloid/exceptions.rb +22 -16
- data/lib/celluloid/fiber.rb +3 -3
- data/lib/celluloid/future.rb +46 -8
- data/lib/celluloid/group/pool.rb +125 -0
- data/lib/celluloid/group/spawner.rb +68 -0
- data/lib/celluloid/group.rb +61 -0
- data/lib/celluloid/logging.rb +5 -5
- data/lib/celluloid/mailbox/evented.rb +74 -0
- data/lib/celluloid/mailbox.rb +15 -14
- data/lib/celluloid/managed.rb +3 -0
- data/lib/celluloid/notices.rb +15 -0
- data/lib/celluloid/proxies.rb +11 -0
- data/lib/celluloid/proxy/abstract.rb +50 -0
- data/lib/celluloid/proxy/actor.rb +37 -0
- data/lib/celluloid/proxy/async.rb +15 -0
- data/lib/celluloid/proxy/block.rb +28 -0
- data/lib/celluloid/proxy/cell.rb +66 -0
- data/lib/celluloid/proxy/future.rb +20 -0
- data/lib/celluloid/proxy/sync.rb +24 -0
- data/lib/celluloid/rspec.rb +67 -9
- data/lib/celluloid/system_events.rb +69 -14
- data/lib/celluloid/task/fibered.rb +45 -0
- data/lib/celluloid/task/threaded.rb +59 -0
- data/lib/celluloid/{tasks.rb → task.rb} +30 -38
- data/lib/celluloid/test.rb +1 -1
- data/lib/celluloid/thread.rb +6 -1
- data/lib/celluloid/version.rb +3 -0
- data/lib/celluloid.rb +151 -130
- data/spec/celluloid/actor/system_spec.rb +83 -0
- data/spec/celluloid/actor_spec.rb +2 -2
- data/spec/celluloid/block_spec.rb +67 -8
- data/spec/celluloid/calls_spec.rb +28 -23
- data/spec/celluloid/condition_spec.rb +23 -14
- data/spec/celluloid/evented_mailbox_spec.rb +1 -31
- data/spec/celluloid/future_spec.rb +15 -12
- data/spec/celluloid/group/elastic_spec.rb +0 -0
- data/spec/celluloid/group/pool_spec.rb +8 -0
- data/spec/celluloid/group/spawner_spec.rb +17 -0
- data/spec/celluloid/mailbox/evented_spec.rb +40 -0
- data/spec/celluloid/mailbox_spec.rb +1 -3
- data/spec/celluloid/misc/leak_spec.rb +73 -0
- data/spec/celluloid/proxy_spec.rb +33 -0
- data/spec/celluloid/task/fibered_spec.rb +5 -0
- data/spec/celluloid/task/threaded_spec.rb +5 -0
- data/spec/celluloid/timer_spec.rb +14 -16
- data/spec/deprecate/actor_system_spec.rb +72 -0
- data/spec/deprecate/block_spec.rb +52 -0
- data/spec/deprecate/calls_spec.rb +39 -0
- data/spec/deprecate/evented_mailbox_spec.rb +34 -0
- data/spec/deprecate/future_spec.rb +32 -0
- data/spec/deprecate/internal_pool_spec.rb +4 -0
- data/spec/shared/actor_examples.rb +1259 -0
- data/spec/shared/group_examples.rb +121 -0
- data/spec/shared/mailbox_examples.rb +87 -0
- data/{lib/celluloid/rspec → spec/shared}/task_examples.rb +9 -8
- data/spec/spec_helper.rb +5 -42
- data/spec/support/configure_rspec.rb +77 -0
- data/spec/support/coverage.rb +4 -0
- data/spec/support/crash_checking.rb +68 -0
- data/spec/support/debugging.rb +31 -0
- data/spec/support/env.rb +21 -0
- data/{lib/celluloid/rspec/example_actor_class.rb → spec/support/examples/actor_class.rb} +21 -2
- data/spec/support/examples/call_class.rb +37 -0
- data/spec/support/examples/evented_mailbox_class.rb +27 -0
- data/spec/support/includer.rb +6 -0
- data/spec/support/logging.rb +55 -0
- data/spec/support/loose_threads.rb +68 -0
- data/spec/support/reset_class_variables.rb +27 -0
- data/spec/support/sleep_and_wait.rb +14 -0
- data/spec/support/stubbing.rb +14 -0
- metadata +276 -78
- data/lib/celluloid/actor_system.rb +0 -107
- data/lib/celluloid/call_chain.rb +0 -13
- data/lib/celluloid/cpu_counter.rb +0 -34
- data/lib/celluloid/evented_mailbox.rb +0 -73
- data/lib/celluloid/fsm.rb +0 -186
- data/lib/celluloid/handlers.rb +0 -41
- data/lib/celluloid/internal_pool.rb +0 -159
- data/lib/celluloid/legacy.rb +0 -9
- data/lib/celluloid/links.rb +0 -36
- data/lib/celluloid/logger.rb +0 -93
- data/lib/celluloid/logging/incident.rb +0 -21
- data/lib/celluloid/logging/incident_logger.rb +0 -129
- data/lib/celluloid/logging/incident_reporter.rb +0 -48
- data/lib/celluloid/logging/log_event.rb +0 -20
- data/lib/celluloid/logging/ring_buffer.rb +0 -65
- data/lib/celluloid/method.rb +0 -32
- data/lib/celluloid/notifications.rb +0 -83
- data/lib/celluloid/pool_manager.rb +0 -146
- data/lib/celluloid/probe.rb +0 -73
- data/lib/celluloid/properties.rb +0 -24
- data/lib/celluloid/proxies/abstract_proxy.rb +0 -20
- data/lib/celluloid/proxies/actor_proxy.rb +0 -38
- data/lib/celluloid/proxies/async_proxy.rb +0 -31
- data/lib/celluloid/proxies/block_proxy.rb +0 -29
- data/lib/celluloid/proxies/cell_proxy.rb +0 -68
- data/lib/celluloid/proxies/future_proxy.rb +0 -35
- data/lib/celluloid/proxies/sync_proxy.rb +0 -36
- data/lib/celluloid/receivers.rb +0 -63
- data/lib/celluloid/registry.rb +0 -57
- data/lib/celluloid/responses.rb +0 -44
- data/lib/celluloid/rspec/actor_examples.rb +0 -1054
- data/lib/celluloid/rspec/mailbox_examples.rb +0 -84
- data/lib/celluloid/signals.rb +0 -23
- data/lib/celluloid/stack_dump.rb +0 -133
- data/lib/celluloid/supervision_group.rb +0 -169
- data/lib/celluloid/supervisor.rb +0 -22
- data/lib/celluloid/task_set.rb +0 -49
- data/lib/celluloid/tasks/task_fiber.rb +0 -43
- data/lib/celluloid/tasks/task_thread.rb +0 -53
- data/lib/celluloid/thread_handle.rb +0 -50
- data/lib/celluloid/uuid.rb +0 -38
- data/spec/celluloid/actor_system_spec.rb +0 -69
- data/spec/celluloid/cpu_counter_spec.rb +0 -82
- data/spec/celluloid/fsm_spec.rb +0 -107
- data/spec/celluloid/internal_pool_spec.rb +0 -52
- data/spec/celluloid/links_spec.rb +0 -45
- data/spec/celluloid/logging/ring_buffer_spec.rb +0 -38
- data/spec/celluloid/notifications_spec.rb +0 -120
- data/spec/celluloid/pool_spec.rb +0 -92
- data/spec/celluloid/probe_spec.rb +0 -121
- data/spec/celluloid/properties_spec.rb +0 -42
- data/spec/celluloid/registry_spec.rb +0 -64
- data/spec/celluloid/stack_dump_spec.rb +0 -64
- data/spec/celluloid/supervision_group_spec.rb +0 -65
- data/spec/celluloid/supervisor_spec.rb +0 -103
- data/spec/celluloid/tasks/task_fiber_spec.rb +0 -5
- data/spec/celluloid/tasks/task_thread_spec.rb +0 -5
- data/spec/celluloid/thread_handle_spec.rb +0 -26
- data/spec/celluloid/uuid_spec.rb +0 -11
data/examples/timers.rb
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
$LOAD_PATH.push File.expand_path("../../lib", __FILE__)
|
|
4
|
+
require "celluloid/current"
|
|
5
|
+
|
|
6
|
+
class TimerExample
|
|
7
|
+
include Celluloid
|
|
8
|
+
attr_reader :fired, :timer
|
|
9
|
+
|
|
10
|
+
def initialize
|
|
11
|
+
@fired = false
|
|
12
|
+
@timer = after(3) { puts "Timer fired!"; @fired = true }
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
#
|
|
17
|
+
# Basic timer example
|
|
18
|
+
#
|
|
19
|
+
|
|
20
|
+
actor = TimerExample.new
|
|
21
|
+
|
|
22
|
+
# The timer hasn't fired yet, so this should be false
|
|
23
|
+
puts "Timer hasn't fired yet, so this should be false: #{actor.fired}"
|
|
24
|
+
|
|
25
|
+
# Even if we wait a second, it still hasn't fired
|
|
26
|
+
sleep 1
|
|
27
|
+
puts "Timer still shouldn't have fired yet: #{actor.fired}"
|
|
28
|
+
|
|
29
|
+
# Wait until after the timer should've fired
|
|
30
|
+
sleep 2.1
|
|
31
|
+
puts "Timer should've fired now: #{actor.fired}"
|
|
32
|
+
|
|
33
|
+
#
|
|
34
|
+
# Cancelling timers
|
|
35
|
+
#
|
|
36
|
+
|
|
37
|
+
actor = TimerExample.new
|
|
38
|
+
|
|
39
|
+
# The timer hasn't fired yet, so this should be false
|
|
40
|
+
puts "Timer hasn't fired yet, so this should be false: #{actor.fired}"
|
|
41
|
+
|
|
42
|
+
# Cancel the timer, which should prevent it from firing
|
|
43
|
+
actor.timer.cancel
|
|
44
|
+
|
|
45
|
+
# Wait until after the timer should've fired
|
|
46
|
+
sleep 3.1
|
|
47
|
+
puts "Timer shouldn't have fired because we cancelled it: #{actor.fired}"
|
|
48
|
+
|
|
49
|
+
class RepeatingTimerExample
|
|
50
|
+
include Celluloid
|
|
51
|
+
|
|
52
|
+
def initialize
|
|
53
|
+
@sheep = 0
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def count_sheep
|
|
57
|
+
print "<#{self.class.name}> Counting sheep to go to sleep: "
|
|
58
|
+
@timer = every(0.1) do
|
|
59
|
+
@sheep += 1
|
|
60
|
+
print @sheep, " "
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def stop_counting
|
|
65
|
+
@timer.cancel
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
sleepy_actor = RepeatingTimerExample.new
|
|
70
|
+
sleepy_actor.count_sheep
|
|
71
|
+
sleep 1
|
|
72
|
+
sleepy_actor.stop_counting
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
module Celluloid
|
|
2
|
+
extend Forwardable
|
|
3
|
+
def_delegators :actor_system, :[], :[]=
|
|
4
|
+
|
|
5
|
+
class Actor
|
|
6
|
+
class System
|
|
7
|
+
extend Forwardable
|
|
8
|
+
def_delegators :@registry, :[], :get, :[]=, :set, :delete
|
|
9
|
+
|
|
10
|
+
ROOT_SERVICES = begin
|
|
11
|
+
root_services = [
|
|
12
|
+
{
|
|
13
|
+
as: :notifications_fanout,
|
|
14
|
+
type: Celluloid::Notifications::Fanout,
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
as: :incident_reporter,
|
|
18
|
+
type: Celluloid::IncidentReporter,
|
|
19
|
+
args: [STDERR],
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
as: :public_services,
|
|
23
|
+
type: Celluloid::Supervision::Service::Public,
|
|
24
|
+
accessors: [:services],
|
|
25
|
+
supervise: [],
|
|
26
|
+
},
|
|
27
|
+
]
|
|
28
|
+
if $CELLULOID_MANAGED
|
|
29
|
+
root_services << {
|
|
30
|
+
as: :actor_manager,
|
|
31
|
+
type: Celluloid::Actor::Manager,
|
|
32
|
+
accessors: [:manager],
|
|
33
|
+
}
|
|
34
|
+
end
|
|
35
|
+
root_services
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
attr_reader :registry, :group
|
|
39
|
+
|
|
40
|
+
# the root of the supervisor tree is established at supervision/root
|
|
41
|
+
|
|
42
|
+
def root_services
|
|
43
|
+
@tree
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def root_configuration
|
|
47
|
+
@root
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def initialize
|
|
51
|
+
@tree = nil
|
|
52
|
+
@group = Celluloid.group_class.new
|
|
53
|
+
@registry = Internals::Registry.new
|
|
54
|
+
@root = ROOT_SERVICES
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Launch default services
|
|
58
|
+
def start
|
|
59
|
+
within do
|
|
60
|
+
@root = Supervision::Service::Root.define
|
|
61
|
+
@tree = root_configuration.deploy
|
|
62
|
+
# de root_services[:group_manager].manage! @group
|
|
63
|
+
end
|
|
64
|
+
true
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def within
|
|
68
|
+
old = Thread.current[:celluloid_actor_system]
|
|
69
|
+
Thread.current[:celluloid_actor_system] = self
|
|
70
|
+
yield
|
|
71
|
+
ensure
|
|
72
|
+
Thread.current[:celluloid_actor_system] = old
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def get_thread
|
|
76
|
+
@group.get do
|
|
77
|
+
Thread.current[:celluloid_actor_system] = self
|
|
78
|
+
yield
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def stack_dump
|
|
83
|
+
Internals::Stack::Dump.new(@group)
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def stack_summary
|
|
87
|
+
Internals::Stack::Summary.new(@group)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def registered
|
|
91
|
+
@registry.names
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def clear_registry
|
|
95
|
+
@registry.clear
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def running
|
|
99
|
+
actors = []
|
|
100
|
+
@group.each do |t|
|
|
101
|
+
next unless t.role == :actor
|
|
102
|
+
actor = t.actor
|
|
103
|
+
|
|
104
|
+
# NOTE - these are in separate statements, since on JRuby t.actor may
|
|
105
|
+
# become nil befor .behavior_proxy() is called
|
|
106
|
+
next unless actor
|
|
107
|
+
next unless actor.respond_to?(:behavior_proxy)
|
|
108
|
+
proxy = actor.behavior_proxy
|
|
109
|
+
actors << proxy
|
|
110
|
+
end
|
|
111
|
+
actors
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def running?
|
|
115
|
+
@group.active?
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Shut down all running actors
|
|
119
|
+
def shutdown
|
|
120
|
+
actors = running
|
|
121
|
+
Timeout.timeout(shutdown_timeout) do
|
|
122
|
+
Internals::Logger.debug "Terminating #{actors.size} #{(actors.size > 1) ? 'actors' : 'actor'}..." if actors.size > 0
|
|
123
|
+
|
|
124
|
+
# Actors cannot self-terminate, you must do it for them
|
|
125
|
+
actors.each do |actor|
|
|
126
|
+
begin
|
|
127
|
+
actor.terminate!
|
|
128
|
+
rescue DeadActorError
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
actors.each do |actor|
|
|
133
|
+
begin
|
|
134
|
+
Actor.join(actor)
|
|
135
|
+
rescue DeadActorError
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
rescue Timeout::Error
|
|
140
|
+
Internals::Logger.error("Couldn't cleanly terminate all actors in #{shutdown_timeout} seconds!")
|
|
141
|
+
unless RUBY_PLATFORM == "java" || RUBY_ENGINE == "rbx"
|
|
142
|
+
actors.each do |actor|
|
|
143
|
+
begin
|
|
144
|
+
Actor.kill(actor)
|
|
145
|
+
rescue DeadActorError, MailboxDead
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
ensure
|
|
150
|
+
@group.shutdown
|
|
151
|
+
clear_registry
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
def assert_inactive
|
|
155
|
+
@group.assert_inactive
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def shutdown_timeout
|
|
159
|
+
Celluloid.shutdown_timeout
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
end
|
data/lib/celluloid/actor.rb
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
require 'timers'
|
|
1
|
+
require "timers"
|
|
3
2
|
|
|
4
3
|
module Celluloid
|
|
5
4
|
# Actors are Celluloid's concurrency primitive. They're implemented as
|
|
@@ -12,37 +11,37 @@ module Celluloid
|
|
|
12
11
|
class << self
|
|
13
12
|
extend Forwardable
|
|
14
13
|
|
|
15
|
-
def_delegators "Celluloid.actor_system", :[], :[]=, :delete, :registered, :clear_registry
|
|
14
|
+
def_delegators :"Celluloid.actor_system", :[], :[]=, :delete, :registered, :clear_registry
|
|
16
15
|
|
|
17
16
|
# Obtain the current actor
|
|
18
17
|
def current
|
|
19
18
|
actor = Thread.current[:celluloid_actor]
|
|
20
|
-
|
|
19
|
+
fail NotActorError, "not in actor scope" unless actor
|
|
21
20
|
actor.behavior_proxy
|
|
22
21
|
end
|
|
23
22
|
|
|
24
23
|
# Obtain the name of the current actor
|
|
25
24
|
def registered_name
|
|
26
25
|
actor = Thread.current[:celluloid_actor]
|
|
27
|
-
|
|
26
|
+
fail NotActorError, "not in actor scope" unless actor
|
|
28
27
|
actor.name
|
|
29
28
|
end
|
|
30
29
|
|
|
31
30
|
# Invoke a method on the given actor via its mailbox
|
|
32
31
|
def call(mailbox, meth, *args, &block)
|
|
33
|
-
proxy =
|
|
32
|
+
proxy = Proxy::Sync.new(mailbox, "UnknownClass")
|
|
34
33
|
proxy.method_missing(meth, *args, &block)
|
|
35
34
|
end
|
|
36
35
|
|
|
37
36
|
# Invoke a method asynchronously on an actor via its mailbox
|
|
38
37
|
def async(mailbox, meth, *args, &block)
|
|
39
|
-
proxy =
|
|
38
|
+
proxy = Proxy::Async.new(mailbox, "UnknownClass")
|
|
40
39
|
proxy.method_missing(meth, *args, &block)
|
|
41
40
|
end
|
|
42
41
|
|
|
43
42
|
# Call a method asynchronously and retrieve its value later
|
|
44
43
|
def future(mailbox, meth, *args, &block)
|
|
45
|
-
proxy =
|
|
44
|
+
proxy = Proxy::Future.new(mailbox, "UnknownClass")
|
|
46
45
|
proxy.method_missing(meth, *args, &block)
|
|
47
46
|
end
|
|
48
47
|
|
|
@@ -53,13 +52,13 @@ module Celluloid
|
|
|
53
52
|
|
|
54
53
|
# Watch for exit events from another actor
|
|
55
54
|
def monitor(actor)
|
|
56
|
-
|
|
55
|
+
fail NotActorError, "can't link outside actor context" unless Celluloid.actor?
|
|
57
56
|
Thread.current[:celluloid_actor].linking_request(actor, :link)
|
|
58
57
|
end
|
|
59
58
|
|
|
60
59
|
# Stop waiting for exit events from another actor
|
|
61
60
|
def unmonitor(actor)
|
|
62
|
-
|
|
61
|
+
fail NotActorError, "can't link outside actor context" unless Celluloid.actor?
|
|
63
62
|
Thread.current[:celluloid_actor].linking_request(actor, :unlink)
|
|
64
63
|
end
|
|
65
64
|
|
|
@@ -85,10 +84,12 @@ module Celluloid
|
|
|
85
84
|
monitoring?(actor) && Thread.current[:celluloid_actor].links.include?(actor)
|
|
86
85
|
end
|
|
87
86
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
actor
|
|
91
|
-
|
|
87
|
+
unless RUBY_PLATFORM == "java" || RUBY_ENGINE == "rbx"
|
|
88
|
+
# Forcibly kill a given actor
|
|
89
|
+
def kill(actor)
|
|
90
|
+
actor.thread.kill
|
|
91
|
+
actor.mailbox.shutdown if actor.mailbox.alive?
|
|
92
|
+
end
|
|
92
93
|
end
|
|
93
94
|
|
|
94
95
|
# Wait for an actor to terminate
|
|
@@ -109,12 +110,12 @@ module Celluloid
|
|
|
109
110
|
@exit_handler = method(:default_exit_handler)
|
|
110
111
|
@exclusive = options.fetch(:exclusive, false)
|
|
111
112
|
|
|
112
|
-
@tasks = TaskSet.new
|
|
113
|
-
@links = Links.new
|
|
114
|
-
@signals = Signals.new
|
|
115
113
|
@timers = Timers::Group.new
|
|
116
|
-
@
|
|
117
|
-
@
|
|
114
|
+
@tasks = Internals::TaskSet.new
|
|
115
|
+
@links = Internals::Links.new
|
|
116
|
+
@handlers = Internals::Handlers.new
|
|
117
|
+
@receivers = Internals::Receivers.new(@timers)
|
|
118
|
+
@signals = Internals::Signals.new
|
|
118
119
|
@running = false
|
|
119
120
|
@name = nil
|
|
120
121
|
|
|
@@ -125,13 +126,14 @@ module Celluloid
|
|
|
125
126
|
|
|
126
127
|
def start
|
|
127
128
|
@running = true
|
|
128
|
-
@thread = ThreadHandle.new(@actor_system, :actor) do
|
|
129
|
+
@thread = Internals::ThreadHandle.new(@actor_system, :actor) do
|
|
129
130
|
setup_thread
|
|
130
131
|
run
|
|
131
132
|
end
|
|
132
133
|
|
|
133
|
-
@proxy =
|
|
134
|
+
@proxy = Proxy::Actor.new(@mailbox, @thread)
|
|
134
135
|
Celluloid::Probe.actor_created(self) if $CELLULOID_MONITORING
|
|
136
|
+
Celluloid::Actor::Manager.actor_created(self) if $CELLULOID_MANAGED
|
|
135
137
|
end
|
|
136
138
|
|
|
137
139
|
def behavior_proxy
|
|
@@ -148,8 +150,8 @@ module Celluloid
|
|
|
148
150
|
while @running
|
|
149
151
|
begin
|
|
150
152
|
@timers.wait do |interval|
|
|
151
|
-
interval = 0 if interval
|
|
152
|
-
|
|
153
|
+
interval = 0 if interval && interval < 0
|
|
154
|
+
|
|
153
155
|
if message = @mailbox.check(interval)
|
|
154
156
|
handle_message(message)
|
|
155
157
|
|
|
@@ -158,13 +160,16 @@ module Celluloid
|
|
|
158
160
|
end
|
|
159
161
|
rescue MailboxShutdown
|
|
160
162
|
@running = false
|
|
163
|
+
rescue MailboxDead
|
|
164
|
+
# TODO: not tests (but fails occasionally in tests)
|
|
165
|
+
@running = false
|
|
161
166
|
end
|
|
162
167
|
end
|
|
163
168
|
|
|
164
169
|
shutdown
|
|
165
|
-
rescue Exception => ex
|
|
170
|
+
rescue ::Exception => ex
|
|
166
171
|
handle_crash(ex)
|
|
167
|
-
raise unless ex.is_a?
|
|
172
|
+
raise unless ex.is_a?(StandardError) || ex.is_a?(Celluloid::Interruption)
|
|
168
173
|
end
|
|
169
174
|
|
|
170
175
|
# Terminate this actor
|
|
@@ -185,25 +190,22 @@ module Celluloid
|
|
|
185
190
|
msg.actor.mailbox.address == receiver.mailbox.address &&
|
|
186
191
|
msg.type == type
|
|
187
192
|
end
|
|
188
|
-
rescue
|
|
193
|
+
rescue TaskTimeout
|
|
189
194
|
next # IO reactor did something, no message in queue yet.
|
|
190
195
|
end
|
|
191
196
|
|
|
192
197
|
if message.instance_of? LinkingResponse
|
|
193
198
|
Celluloid::Probe.actors_linked(self, receiver) if $CELLULOID_MONITORING
|
|
194
|
-
|
|
195
|
-
# We're done!
|
|
196
199
|
system_events.each { |ev| @mailbox << ev }
|
|
197
|
-
|
|
198
200
|
return
|
|
199
201
|
elsif message.is_a? SystemEvent
|
|
200
202
|
# Queue up pending system events to be processed after we've successfully linked
|
|
201
203
|
system_events << message
|
|
202
|
-
else
|
|
204
|
+
else fail "Unexpected message type: #{message.class}. Expected LinkingResponse, NilClass, SystemEvent."
|
|
203
205
|
end
|
|
204
206
|
end
|
|
205
207
|
|
|
206
|
-
|
|
208
|
+
fail TaskTimeout, "linking timeout of #{LINKING_TIMEOUT} seconds exceeded with receiver: #{receiver}"
|
|
207
209
|
end
|
|
208
210
|
end
|
|
209
211
|
|
|
@@ -216,16 +218,17 @@ module Celluloid
|
|
|
216
218
|
def wait(name)
|
|
217
219
|
@signals.wait name
|
|
218
220
|
end
|
|
219
|
-
|
|
221
|
+
|
|
222
|
+
# Register a new handler for a given pattern
|
|
220
223
|
def handle(*patterns, &block)
|
|
221
224
|
@handlers.handle(*patterns, &block)
|
|
222
225
|
end
|
|
223
226
|
|
|
224
227
|
# Receive an asynchronous message
|
|
225
228
|
def receive(timeout = nil, &block)
|
|
226
|
-
|
|
229
|
+
while true
|
|
227
230
|
message = @receivers.receive(timeout, &block)
|
|
228
|
-
|
|
231
|
+
return message unless message.is_a?(SystemEvent)
|
|
229
232
|
|
|
230
233
|
handle_system_event(message)
|
|
231
234
|
end
|
|
@@ -245,7 +248,7 @@ module Celluloid
|
|
|
245
248
|
bt = caller
|
|
246
249
|
task = Task.current
|
|
247
250
|
timer = @timers.after(duration) do
|
|
248
|
-
exception =
|
|
251
|
+
exception = TaskTimeout.new("execution expired")
|
|
249
252
|
exception.set_backtrace bt
|
|
250
253
|
task.resume exception
|
|
251
254
|
end
|
|
@@ -279,48 +282,23 @@ module Celluloid
|
|
|
279
282
|
def handle_message(message)
|
|
280
283
|
unless @handlers.handle_message(message)
|
|
281
284
|
unless @receivers.handle_message(message)
|
|
282
|
-
Logger.debug "Discarded message (unhandled): #{message}" if $CELLULOID_DEBUG
|
|
285
|
+
Internals::Logger.debug "Discarded message (unhandled): #{message}" if $CELLULOID_DEBUG
|
|
283
286
|
end
|
|
284
287
|
end
|
|
285
288
|
message
|
|
286
289
|
end
|
|
287
290
|
|
|
288
|
-
# Handle high-priority system event messages
|
|
289
|
-
def handle_system_event(event)
|
|
290
|
-
if event.instance_of? ExitEvent
|
|
291
|
-
handle_exit_event(event)
|
|
292
|
-
elsif event.instance_of? LinkingRequest
|
|
293
|
-
event.process(links)
|
|
294
|
-
elsif event.instance_of? NamingRequest
|
|
295
|
-
@name = event.name
|
|
296
|
-
Celluloid::Probe.actor_named(self) if $CELLULOID_MONITORING
|
|
297
|
-
elsif event.instance_of? TerminationRequest
|
|
298
|
-
terminate
|
|
299
|
-
elsif event.instance_of? SignalConditionRequest
|
|
300
|
-
event.call
|
|
301
|
-
else
|
|
302
|
-
Logger.debug "Discarded message (unhandled): #{message}" if $CELLULOID_DEBUG
|
|
303
|
-
end
|
|
304
|
-
end
|
|
305
|
-
|
|
306
|
-
# Handle exit events received by this actor
|
|
307
|
-
def handle_exit_event(event)
|
|
308
|
-
@links.delete event.actor
|
|
309
|
-
|
|
310
|
-
@exit_handler.call(event)
|
|
311
|
-
end
|
|
312
|
-
|
|
313
291
|
def default_exit_handler(event)
|
|
314
|
-
|
|
292
|
+
fail event.reason if event.reason
|
|
315
293
|
end
|
|
316
294
|
|
|
317
295
|
# Handle any exceptions that occur within a running actor
|
|
318
296
|
def handle_crash(exception)
|
|
319
297
|
# TODO: add meta info
|
|
320
|
-
Logger.crash("Actor crashed!", exception)
|
|
298
|
+
Internals::Logger.crash("Actor crashed!", exception)
|
|
321
299
|
shutdown ExitEvent.new(behavior_proxy, exception)
|
|
322
300
|
rescue => ex
|
|
323
|
-
Logger.crash("
|
|
301
|
+
Internals::Logger.crash("Actor#handle_crash CRASHED!", ex)
|
|
324
302
|
end
|
|
325
303
|
|
|
326
304
|
# Handle cleaning up this actor after it exits
|
|
@@ -337,26 +315,30 @@ module Celluloid
|
|
|
337
315
|
Celluloid::Probe.actor_died(self) if $CELLULOID_MONITORING
|
|
338
316
|
@mailbox.shutdown
|
|
339
317
|
@links.each do |actor|
|
|
340
|
-
if actor.mailbox.alive?
|
|
341
|
-
actor.mailbox << exit_event
|
|
342
|
-
end
|
|
318
|
+
actor.mailbox << exit_event if actor.mailbox.alive?
|
|
343
319
|
end
|
|
344
320
|
|
|
345
|
-
tasks.to_a.each
|
|
321
|
+
tasks.to_a.each do |task|
|
|
322
|
+
begin
|
|
323
|
+
task.terminate
|
|
324
|
+
rescue DeadTaskError
|
|
325
|
+
# TODO: not tested (failed on Travis)
|
|
326
|
+
end
|
|
327
|
+
end
|
|
346
328
|
rescue => ex
|
|
347
329
|
# TODO: metadata
|
|
348
|
-
Logger.crash("CLEANUP CRASHED!", ex)
|
|
330
|
+
Internals::Logger.crash("CLEANUP CRASHED!", ex)
|
|
349
331
|
end
|
|
350
332
|
|
|
351
333
|
# Run a method inside a task unless it's exclusive
|
|
352
334
|
def task(task_type, meta = nil)
|
|
353
|
-
@task_class.new(task_type, meta)
|
|
335
|
+
@task_class.new(task_type, meta) do
|
|
354
336
|
if @exclusive
|
|
355
337
|
Celluloid.exclusive { yield }
|
|
356
338
|
else
|
|
357
339
|
yield
|
|
358
340
|
end
|
|
359
|
-
|
|
341
|
+
end.resume
|
|
360
342
|
end
|
|
361
343
|
end
|
|
362
344
|
end
|
data/lib/celluloid/autostart.rb
CHANGED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module Celluloid
|
|
2
|
+
class Call
|
|
3
|
+
# Asynchronous calls don't wait for a response
|
|
4
|
+
class Async < Call
|
|
5
|
+
def dispatch(obj)
|
|
6
|
+
Internals::CallChain.current_id = Celluloid.uuid
|
|
7
|
+
super(obj)
|
|
8
|
+
rescue AbortError => ex
|
|
9
|
+
# Swallow aborted async calls, as they indicate the sender made a mistake
|
|
10
|
+
Internals::Logger.debug("#{obj.class}: async call `#{@method}` aborted!\n#{Internals::Logger.format_exception(ex.cause)}")
|
|
11
|
+
ensure
|
|
12
|
+
Internals::CallChain.current_id = nil
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
module Celluloid
|
|
2
|
+
class Call
|
|
3
|
+
class Block
|
|
4
|
+
def initialize(block_proxy, sender, arguments, task = Thread.current[:celluloid_task])
|
|
5
|
+
@block_proxy = block_proxy
|
|
6
|
+
@sender = sender
|
|
7
|
+
@arguments = arguments
|
|
8
|
+
@task = task
|
|
9
|
+
end
|
|
10
|
+
attr_reader :task
|
|
11
|
+
|
|
12
|
+
def call
|
|
13
|
+
@block_proxy.call
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def dispatch
|
|
17
|
+
response = @block_proxy.block.call(*@arguments)
|
|
18
|
+
@sender << Internals::Response::Block.new(self, response)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module Celluloid
|
|
2
|
+
class Call
|
|
3
|
+
# Synchronous calls wait for a response
|
|
4
|
+
class Sync < Call
|
|
5
|
+
attr_reader :sender, :task, :chain_id
|
|
6
|
+
|
|
7
|
+
def initialize(sender, method, arguments = [], block = nil, task = Thread.current[:celluloid_task], chain_id = Internals::CallChain.current_id)
|
|
8
|
+
super(method, arguments, block)
|
|
9
|
+
@sender = sender
|
|
10
|
+
@task = task
|
|
11
|
+
@chain_id = chain_id || Celluloid.uuid
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def dispatch(obj)
|
|
15
|
+
Internals::CallChain.current_id = @chain_id
|
|
16
|
+
result = super(obj)
|
|
17
|
+
respond Internals::Response::Success.new(self, result)
|
|
18
|
+
rescue ::Exception => ex
|
|
19
|
+
# Exceptions that occur during synchronous calls are reraised in the
|
|
20
|
+
# context of the sender
|
|
21
|
+
respond Internals::Response::Error.new(self, ex)
|
|
22
|
+
|
|
23
|
+
# Aborting indicates a protocol error on the part of the sender
|
|
24
|
+
# It should crash the sender, but the exception isn't reraised
|
|
25
|
+
# Otherwise, it's a bug in this actor and should be reraised
|
|
26
|
+
raise unless ex.is_a?(AbortError)
|
|
27
|
+
ensure
|
|
28
|
+
Internals::CallChain.current_id = nil
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def cleanup
|
|
32
|
+
exception = DeadActorError.new("attempted to call a dead actor: #{self.method}")
|
|
33
|
+
respond Internals::Response::Error.new(self, exception)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def respond(message)
|
|
37
|
+
@sender << message
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def response
|
|
41
|
+
Celluloid.suspend(:callwait, self)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def value
|
|
45
|
+
response.value
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def wait
|
|
49
|
+
while true
|
|
50
|
+
message = Celluloid.mailbox.receive do |msg|
|
|
51
|
+
msg.respond_to?(:call) && msg.call == self
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
if message.is_a?(SystemEvent)
|
|
55
|
+
Thread.current[:celluloid_actor].handle_system_event(message)
|
|
56
|
+
else
|
|
57
|
+
# FIXME: add check for receiver block execution
|
|
58
|
+
if message.respond_to?(:value)
|
|
59
|
+
# FIXME: disable block execution if on :sender and (exclusive or outside of task)
|
|
60
|
+
# probably now in Call
|
|
61
|
+
return message
|
|
62
|
+
else
|
|
63
|
+
message.dispatch
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|