tribe 0.3.2 → 0.4.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/Gemfile.lock +1 -1
- data/README.md +67 -70
- data/lib/tribe/actable.rb +45 -31
- data/lib/tribe/future.rb +38 -5
- data/lib/tribe/root.rb +19 -0
- data/lib/tribe/version.rb +1 -1
- data/lib/tribe.rb +7 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 865a31569730f5bc15800bc24f0dc791faea2971
|
4
|
+
data.tar.gz: c7a793ff5df24f85ddf2d0f877fd5a892f946fe6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ec0d7842dd09a91e305da5719b19bea9a5aa584edcf39a522036f5668c05fac9efaafb442f8706c6766080b15b69e3f47d6edf778b56443439b2a0b567703ce8
|
7
|
+
data.tar.gz: 28bd5c028b349ac7ed29d45593aae3a888e55d280fa7a927f6d3614e4bd4476c382fce95401ede14e04b2ddd0408b777a0b00fd3630703a2d0ed37ee0c960fb4
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -13,6 +13,9 @@ Event-driven servers can be built using [Tribe EM] (https://github.com/chadrem/t
|
|
13
13
|
|
14
14
|
- [Installation](#installation)
|
15
15
|
- [Actors](#actors)
|
16
|
+
- [Root](#root-actor)
|
17
|
+
- [Handlers](#handlers)
|
18
|
+
- [Messages](#messages)
|
16
19
|
- [Registries](#registries)
|
17
20
|
- [Timers](#timers)
|
18
21
|
- [Futures](#futures)
|
@@ -42,18 +45,34 @@ Or install it yourself as:
|
|
42
45
|
|
43
46
|
## Actors
|
44
47
|
|
45
|
-
Actors are
|
46
|
-
There are
|
48
|
+
Actors are the building blocks of your application.
|
49
|
+
There are three ways to create an actor class:
|
50
|
+
|
51
|
+
- Inherit from Tribe::Actor (uses the shared thread pool).
|
52
|
+
- Inherit from Tribe::DedicatedActor (uses a dedicated thread).
|
53
|
+
- Mixin Tribe::Actable and call the Actable#init_actable method in your constructor.
|
54
|
+
|
55
|
+
|
56
|
+
#### Root
|
57
|
+
|
58
|
+
Well designed applications built with the actor model tend to organize their actors in a tree like structure.
|
59
|
+
To encourage this, Tribe has a special built-in actor known as the root actor.
|
60
|
+
You should use this actor to spawn all of your application specific actors.
|
61
|
+
|
62
|
+
Tribe.root
|
63
|
+
|
64
|
+
#### Handlers
|
65
|
+
|
66
|
+
There are two types of methods that you create in your actor classes:
|
47
67
|
|
48
68
|
1. *Command handlers* are prefixed with "on_" and define the types of commands your actor will process.
|
49
69
|
2. *System handlers* are postfixed with "_handler" and are built into the actor system. These are hooks into the Tribe's actor system.
|
50
70
|
|
51
|
-
|
52
|
-
The return value will always be nil since messaging is asynchronous.
|
71
|
+
#### Messages
|
53
72
|
|
54
|
-
|
55
|
-
|
56
|
-
|
73
|
+
Actors communicate asynchronously using a number of methods that end in ! (exclamation point or “bang”).
|
74
|
+
The most basic type of communication is a message and they are sent using using the Actable#message! and Actable#deliver_message! methods.
|
75
|
+
These methods always return nil since they are fire-and-forget.
|
57
76
|
|
58
77
|
# Create your custom actor class.
|
59
78
|
class MyActor < Tribe::Actor
|
@@ -73,15 +92,15 @@ More information on them will be provided throughout this readme.
|
|
73
92
|
end
|
74
93
|
end
|
75
94
|
|
76
|
-
# Create some named actors.
|
95
|
+
# Create some named actors that are children of the root actor.
|
77
96
|
100.times do |i|
|
78
|
-
|
97
|
+
Tribe.root.spawn(MyActor, :name => "my_actor_#{i}")
|
79
98
|
end
|
80
99
|
|
81
100
|
# Send an event to each actor.
|
82
101
|
100.times do |i|
|
83
102
|
actor = Tribe.registry["my_actor_#{i}"]
|
84
|
-
actor.
|
103
|
+
actor.deliver_message!(:my_custom, 'hello world')
|
85
104
|
end
|
86
105
|
|
87
106
|
# Shutdown the actors.
|
@@ -90,27 +109,12 @@ More information on them will be provided throughout this readme.
|
|
90
109
|
actor.shutdown!
|
91
110
|
end
|
92
111
|
|
93
|
-
#### Implementation
|
94
|
-
Because actors use a shared thread pool, it is important that they don't block for long periods of time (short periods are fine).
|
95
|
-
Actors that block for long periods of time should use a dedicated thread (:dedicated => true or subclass from Tribe::DedicatedActor).
|
96
|
-
|
97
|
-
#### Options (defaults below)
|
98
|
-
|
99
|
-
actor = Tribe::Actor.new(
|
100
|
-
:logger => nil, # Ruby logger instance.
|
101
|
-
:dedicated => false, # If true, the actor runs with a worker pool that has one thread.
|
102
|
-
:pool => Workers.pool, # The workers pool used to execute events.
|
103
|
-
:registry => Tribe.registry, # The registry used to store a reference to the actor if it has a name.
|
104
|
-
:name => nil, # The name of the actor (must be unique in the registry).
|
105
|
-
:parent => nil # Set the parent actor (used by the supervision feature).
|
106
|
-
)
|
107
|
-
|
108
112
|
## Registries
|
109
113
|
|
110
114
|
Registries hold references to named actors so that you can easily find them.
|
111
115
|
In general you shouldn't have to create your own since there is a global one (Tribe.registry).
|
112
116
|
|
113
|
-
actor = Tribe::Actor
|
117
|
+
actor = Tribe.root.spawn(Tribe::Actor, :name => 'some_actor')
|
114
118
|
|
115
119
|
if actor == Tribe.registry['some_actor']
|
116
120
|
puts 'Successfully found some_actor in the registry.'
|
@@ -140,7 +144,7 @@ Both one-shot and periodic timers are provided.
|
|
140
144
|
|
141
145
|
# Create some named actors.
|
142
146
|
10.times do |i|
|
143
|
-
|
147
|
+
Tribe.root.spawn(MyActor, :name => "my_actor_#{i}")
|
144
148
|
end
|
145
149
|
|
146
150
|
# Sleep in order to observe the timers.
|
@@ -154,9 +158,9 @@ Both one-shot and periodic timers are provided.
|
|
154
158
|
|
155
159
|
## Futures
|
156
160
|
|
157
|
-
|
161
|
+
Message passing with the Actable#message! and Actable#deliver_message! methods is asynchronous and always returns nil.
|
158
162
|
This can be a pain since in many cases you will be interested in the result.
|
159
|
-
The Actable#future! method solves this problem by returning a Tribe::Future object
|
163
|
+
The Actable#future! method solves this problem by returning a Tribe::Future object.
|
160
164
|
You can then use this object to obtain the result when it becomes available.
|
161
165
|
|
162
166
|
#### Non-blocking
|
@@ -173,19 +177,14 @@ No waiting for a result is involved and the actor will continue to process other
|
|
173
177
|
|
174
178
|
def on_start(event)
|
175
179
|
friend = registry['actor_b']
|
176
|
-
|
177
|
-
future = friend.future!(:compute, 10)
|
180
|
+
future = future!(friend, :compute, 10)
|
178
181
|
|
179
182
|
future.success do |result|
|
180
|
-
|
181
|
-
puts "ActorA (#{identifier}) future result: #{result}"
|
182
|
-
end
|
183
|
+
puts "ActorA (#{identifier}) future result: #{result}"
|
183
184
|
end
|
184
185
|
|
185
186
|
future.failure do |exception|
|
186
|
-
|
187
|
-
puts "ActorA (#{identifier}) future failure: #{exception}"
|
188
|
-
end
|
187
|
+
puts "ActorA (#{identifier}) future failure: #{exception}"
|
189
188
|
end
|
190
189
|
end
|
191
190
|
end
|
@@ -206,18 +205,14 @@ No waiting for a result is involved and the actor will continue to process other
|
|
206
205
|
end
|
207
206
|
end
|
208
207
|
|
209
|
-
actor_a =
|
210
|
-
actor_b =
|
208
|
+
actor_a = Tribe.root.spawn(ActorA, :name => 'actor_a')
|
209
|
+
actor_b = Tribe.root.spawn(ActorB, :name => 'actor_b')
|
211
210
|
|
212
|
-
actor_a.
|
211
|
+
actor_a.deliver_message!(:start)
|
213
212
|
|
214
213
|
actor_a.shutdown!
|
215
214
|
actor_b.shutdown!
|
216
215
|
|
217
|
-
*Important*: You must use Actable#perform! inside the above callbacks.
|
218
|
-
This ensures that your code executes within the context of the correct actor.
|
219
|
-
Failure to do so will result in unexpected behavior (thread safety will be lost)!
|
220
|
-
|
221
216
|
#### Blocking
|
222
217
|
|
223
218
|
Blocking futures are synchronous.
|
@@ -232,8 +227,7 @@ The actor won't process any other events until the future has a result.
|
|
232
227
|
|
233
228
|
def on_start(event)
|
234
229
|
friend = registry['actor_b']
|
235
|
-
|
236
|
-
future = friend.future!(:compute, 10)
|
230
|
+
future = future!(friend, :compute, 10)
|
237
231
|
|
238
232
|
future.wait # The current thread will sleep until a result is available.
|
239
233
|
|
@@ -261,10 +255,10 @@ The actor won't process any other events until the future has a result.
|
|
261
255
|
end
|
262
256
|
end
|
263
257
|
|
264
|
-
actor_a =
|
265
|
-
actor_b =
|
258
|
+
actor_a = Tribe.root.spawn(ActorA, :name => 'actor_a')
|
259
|
+
actor_b = Tribe.root.spawn(ActorB, :name => 'actor_b')
|
266
260
|
|
267
|
-
actor_a.
|
261
|
+
actor_a.deliver_message!(:start)
|
268
262
|
|
269
263
|
actor_a.shutdown!
|
270
264
|
actor_b.shutdown!
|
@@ -274,7 +268,7 @@ The actor won't process any other events until the future has a result.
|
|
274
268
|
Futures can be confgured to timeout after a specified number of seconds.
|
275
269
|
When a timeout occurs, the result of the future will be a Tribe::FutureTimeout exception.
|
276
270
|
|
277
|
-
# Manually create a future (Use Actable#future! in your actors).
|
271
|
+
# Manually create a future for this example (Use Actable#future! in your actors).
|
278
272
|
future = Tribe::Future.new
|
279
273
|
|
280
274
|
# Set a timeout (in seconds).
|
@@ -342,11 +336,11 @@ This lets you build routers that delegate work to other actors.
|
|
342
336
|
end
|
343
337
|
|
344
338
|
# Create the router.
|
345
|
-
router =
|
339
|
+
router = Tribe.root.spawn(MyRouter, :name => 'router')
|
346
340
|
|
347
341
|
# Send an event to the router and it will forward it to a random processor.
|
348
342
|
100.times do |i|
|
349
|
-
router.
|
343
|
+
router.deliver_message!(:process, i)
|
350
344
|
end
|
351
345
|
|
352
346
|
# Shutdown the router.
|
@@ -355,11 +349,12 @@ This lets you build routers that delegate work to other actors.
|
|
355
349
|
## Linking
|
356
350
|
|
357
351
|
Linking allows actors to group together into a tree structure such that they all live or die as one group.
|
358
|
-
Such linking is useful for breaking complex problems into smaller
|
359
|
-
To create a linked actor you use the Actable#spawn method
|
360
|
-
|
352
|
+
Such linking is useful for breaking up complex problems into multiple smaller units.
|
353
|
+
To create a linked actor you use the Actable#spawn method.
|
354
|
+
By default, if a linked actor dies, it will cause its parent and children to die too.
|
355
|
+
Thus the entire tree lives or dies together.
|
361
356
|
|
362
|
-
# Create the
|
357
|
+
# Create the top-level actor class.
|
363
358
|
class Level1 < Tribe::Actor
|
364
359
|
private
|
365
360
|
def on_spawn(event)
|
@@ -367,7 +362,7 @@ If any actor in a tree of linked actors dies, it will cause all actors above and
|
|
367
362
|
name = "level2_#{i}"
|
368
363
|
puts name
|
369
364
|
actor = spawn(Level2, :name => name)
|
370
|
-
|
365
|
+
message!(actor, :spawn, i)
|
371
366
|
end
|
372
367
|
end
|
373
368
|
end
|
@@ -379,7 +374,7 @@ If any actor in a tree of linked actors dies, it will cause all actors above and
|
|
379
374
|
5.times do |i|
|
380
375
|
name = "level3_#{event.data}_#{i}"
|
381
376
|
actor = spawn(Level3, :name => name)
|
382
|
-
|
377
|
+
message!(actor, :spawn)
|
383
378
|
end
|
384
379
|
end
|
385
380
|
end
|
@@ -392,18 +387,19 @@ If any actor in a tree of linked actors dies, it will cause all actors above and
|
|
392
387
|
end
|
393
388
|
end
|
394
389
|
|
395
|
-
# Create the
|
396
|
-
|
390
|
+
# Create the top-level actor.
|
391
|
+
top = Tribe.root.spawn(Level1, :name => 'level1')
|
397
392
|
|
398
393
|
# Tell the root actor to create the tree of children.
|
399
|
-
|
394
|
+
top.deliver_message!(:spawn)
|
400
395
|
|
401
396
|
## Supervisors
|
402
397
|
|
403
|
-
|
404
|
-
Supervisors can be used to block the failure from propogating
|
398
|
+
A failure in a linked actor will cause all associated actors (parent and children) to die.
|
399
|
+
Supervisors can be used to block the failure from propogating.
|
400
|
+
You then have the option to re-create the failed actor.
|
405
401
|
|
406
|
-
# Create the
|
402
|
+
# Create the top-level actor class.
|
407
403
|
class Level1 < Tribe::Actor
|
408
404
|
private
|
409
405
|
def on_spawn(event)
|
@@ -414,7 +410,7 @@ Supervisors can be used to block the failure from propogating and allow you to r
|
|
414
410
|
|
415
411
|
def create_subtree
|
416
412
|
actor = spawn(Level2)
|
417
|
-
|
413
|
+
message!(actor, :spawn)
|
418
414
|
end
|
419
415
|
|
420
416
|
def child_died_handler(actor, exception)
|
@@ -429,7 +425,7 @@ Supervisors can be used to block the failure from propogating and allow you to r
|
|
429
425
|
def on_spawn(event)
|
430
426
|
5.times do |i|
|
431
427
|
actor = spawn(Level3)
|
432
|
-
|
428
|
+
message!(actor, :spawn)
|
433
429
|
end
|
434
430
|
end
|
435
431
|
end
|
@@ -443,13 +439,14 @@ Supervisors can be used to block the failure from propogating and allow you to r
|
|
443
439
|
end
|
444
440
|
end
|
445
441
|
|
446
|
-
# Create the
|
447
|
-
|
442
|
+
# Create the top-level actor.
|
443
|
+
top = Tribe.root.spawn(Level1, :name => 'root')
|
448
444
|
|
449
|
-
# Tell the
|
450
|
-
|
445
|
+
# Tell the top-level actor to create the tree of children.
|
446
|
+
top.deliver_message!(:spawn)
|
451
447
|
|
452
448
|
#### Important!
|
449
|
+
|
453
450
|
Restarting named actors is NOT currently supported, but will be in a future update.
|
454
451
|
Attempting to do so may result in Tribe::RegistryError exceptions when trying to spawn a replacement child.
|
455
452
|
|
data/lib/tribe/actable.rb
CHANGED
@@ -37,35 +37,64 @@ module Tribe
|
|
37
37
|
|
38
38
|
public
|
39
39
|
|
40
|
-
def
|
41
|
-
|
40
|
+
def deliver_event!(event)
|
41
|
+
@_as.mailbox.push(event) do
|
42
|
+
process_events
|
43
|
+
end
|
44
|
+
|
45
|
+
return nil
|
46
|
+
end
|
47
|
+
|
48
|
+
def deliver_message!(command, data = nil, src = nil)
|
49
|
+
deliver_event!(Tribe::Event.new(command, data, src))
|
42
50
|
|
43
51
|
return nil
|
44
52
|
end
|
45
53
|
|
46
|
-
def message!(command, data = nil
|
47
|
-
event = Tribe::Event.new(command, data,
|
54
|
+
def message!(dest, command, data = nil)
|
55
|
+
event = Tribe::Event.new(command, data, self)
|
48
56
|
|
49
|
-
|
57
|
+
dest.deliver_event!(event)
|
50
58
|
|
51
59
|
return nil
|
52
60
|
end
|
53
61
|
|
54
|
-
def future!(command, data = nil
|
55
|
-
event = Tribe::Event.new(command, data,
|
56
|
-
event.future = future = Tribe::Future.new
|
62
|
+
def future!(dest, command, data = nil)
|
63
|
+
event = Tribe::Event.new(command, data, self)
|
64
|
+
event.future = future = Tribe::Future.new(self)
|
57
65
|
|
58
|
-
|
66
|
+
dest.deliver_event!(event)
|
59
67
|
|
60
68
|
return future
|
61
69
|
end
|
62
70
|
|
63
71
|
def shutdown!
|
64
|
-
return
|
72
|
+
return deliver_message!(:_shutdown)
|
65
73
|
end
|
66
74
|
|
67
75
|
def perform!(&block)
|
68
|
-
return
|
76
|
+
return deliver_message!(:_perform, block)
|
77
|
+
end
|
78
|
+
|
79
|
+
def spawn(klass, actor_options = {}, spawn_options = {})
|
80
|
+
actor_options[:parent] = self
|
81
|
+
|
82
|
+
@_as.children ||= []
|
83
|
+
child = nil
|
84
|
+
|
85
|
+
if spawn_options[:no_raise_on_failure]
|
86
|
+
begin
|
87
|
+
child = klass.new(actor_options)
|
88
|
+
rescue Exception => e
|
89
|
+
return false
|
90
|
+
end
|
91
|
+
else
|
92
|
+
child = klass.new(actor_options)
|
93
|
+
end
|
94
|
+
|
95
|
+
@_as.children << child
|
96
|
+
|
97
|
+
return child
|
69
98
|
end
|
70
99
|
|
71
100
|
def alive?
|
@@ -108,11 +137,11 @@ module Tribe
|
|
108
137
|
|
109
138
|
def exception_handler(exception)
|
110
139
|
if @_as.parent
|
111
|
-
@_as.parent.
|
140
|
+
@_as.parent.deliver_message!(:_child_died, [self, exception])
|
112
141
|
end
|
113
142
|
|
114
143
|
if @_as.children
|
115
|
-
@_as.children.each { |c| c.
|
144
|
+
@_as.children.each { |c| c.deliver_message!(:_parent_died, [self, exception]) }
|
116
145
|
@_as.children.clear
|
117
146
|
@_as.children = nil
|
118
147
|
end
|
@@ -176,7 +205,7 @@ module Tribe
|
|
176
205
|
|
177
206
|
timer = Workers::Timer.new(delay, :scheduler => @_as.scheduler) do
|
178
207
|
@_as.timers.delete(timer)
|
179
|
-
|
208
|
+
deliver_message!(command, data)
|
180
209
|
end
|
181
210
|
|
182
211
|
@_as.timers.add(timer)
|
@@ -190,7 +219,7 @@ module Tribe
|
|
190
219
|
@_as.timers ||= Tribe::SafeSet.new
|
191
220
|
|
192
221
|
timer = Workers::PeriodicTimer.new(delay, :scheduler => @_as.scheduler) do
|
193
|
-
|
222
|
+
deliver_message!(command, data)
|
194
223
|
unless alive?
|
195
224
|
@_as.timers.delete(timer)
|
196
225
|
timer.cancel
|
@@ -208,27 +237,12 @@ module Tribe
|
|
208
237
|
#
|
209
238
|
|
210
239
|
def forward!(dest)
|
211
|
-
dest.
|
240
|
+
dest.deliver_event!(@_as.active_event)
|
212
241
|
@_as.active_event = nil
|
213
242
|
|
214
243
|
return nil
|
215
244
|
end
|
216
245
|
|
217
|
-
def spawn(klass, options = {})
|
218
|
-
options[:parent] = self
|
219
|
-
|
220
|
-
@_as.children ||= []
|
221
|
-
@_as.children << (actor = klass.new(options))
|
222
|
-
|
223
|
-
return actor
|
224
|
-
end
|
225
|
-
|
226
|
-
def push_event(event)
|
227
|
-
@_as.mailbox.push(event) do
|
228
|
-
process_events
|
229
|
-
end
|
230
|
-
end
|
231
|
-
|
232
246
|
# All system commands are prefixed with an underscore.
|
233
247
|
def process_events
|
234
248
|
while (event = @_as.mailbox.obtain_and_shift)
|
data/lib/tribe/future.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
module Tribe
|
2
2
|
class Future
|
3
|
-
def initialize
|
3
|
+
def initialize(actor = nil)
|
4
4
|
@state = :initialized
|
5
5
|
@mutex = Mutex.new
|
6
6
|
@condition = ConditionVariable.new
|
7
7
|
@result = nil
|
8
8
|
@success_callback = nil
|
9
9
|
@failure_callback = nil
|
10
|
+
@actor = actor
|
10
11
|
|
11
12
|
return nil
|
12
13
|
end
|
@@ -34,9 +35,25 @@ module Tribe
|
|
34
35
|
@condition.signal
|
35
36
|
|
36
37
|
if val.is_a?(Exception)
|
37
|
-
|
38
|
+
if @failure_callback
|
39
|
+
if @actor
|
40
|
+
@actor.perform! do
|
41
|
+
@failure_callback.call(val)
|
42
|
+
end
|
43
|
+
else
|
44
|
+
@failure_callback.call(val)
|
45
|
+
end
|
46
|
+
end
|
38
47
|
else
|
39
|
-
|
48
|
+
if @success_callback
|
49
|
+
if @actor
|
50
|
+
@actor.perform! do
|
51
|
+
@success_callback.call(val)
|
52
|
+
end
|
53
|
+
else
|
54
|
+
@success_callback.call(val)
|
55
|
+
end
|
56
|
+
end
|
40
57
|
end
|
41
58
|
|
42
59
|
return nil
|
@@ -79,7 +96,15 @@ module Tribe
|
|
79
96
|
when :initialized
|
80
97
|
@success_callback = block
|
81
98
|
when :finished
|
82
|
-
|
99
|
+
unless @result.is_a?(Exception)
|
100
|
+
if @actor
|
101
|
+
@actor.perform! do
|
102
|
+
block.call(@result)
|
103
|
+
end
|
104
|
+
else
|
105
|
+
block.call(@result)
|
106
|
+
end
|
107
|
+
end
|
83
108
|
else
|
84
109
|
raise Tribe::FutureError.new('Invalid state.')
|
85
110
|
end
|
@@ -94,7 +119,15 @@ module Tribe
|
|
94
119
|
when :initialized
|
95
120
|
@failure_callback = block
|
96
121
|
when :finished
|
97
|
-
|
122
|
+
if @result.is_a?(Exception)
|
123
|
+
if @actor
|
124
|
+
@actor.perform! do
|
125
|
+
block.call(@result)
|
126
|
+
end
|
127
|
+
else
|
128
|
+
block.call(@result)
|
129
|
+
end
|
130
|
+
end
|
98
131
|
else
|
99
132
|
raise Tribe::FutureError.new('Invalid state.')
|
100
133
|
end
|
data/lib/tribe/root.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
module Tribe
|
2
|
+
class Root < Tribe::Actor
|
3
|
+
private
|
4
|
+
|
5
|
+
def initialize(options = {})
|
6
|
+
unless options[:permit_root]
|
7
|
+
raise 'Application code should never create the root actor.'
|
8
|
+
end
|
9
|
+
|
10
|
+
options.delete(:permit_root)
|
11
|
+
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def child_died_handler(child, exception)
|
16
|
+
# Let the children die silently since the root actor should live forever.
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/tribe/version.rb
CHANGED
data/lib/tribe.rb
CHANGED
@@ -12,6 +12,7 @@ require 'tribe/actor'
|
|
12
12
|
require 'tribe/dedicated_actor'
|
13
13
|
require 'tribe/registry'
|
14
14
|
require 'tribe/future'
|
15
|
+
require 'tribe/root'
|
15
16
|
|
16
17
|
module Tribe
|
17
18
|
def self.registry
|
@@ -22,7 +23,12 @@ module Tribe
|
|
22
23
|
@registry.dispose if @registry
|
23
24
|
@registry = val
|
24
25
|
end
|
26
|
+
|
27
|
+
def self.root
|
28
|
+
@root ||= Tribe::Root.new(:name => 'root', :permit_root => true)
|
29
|
+
end
|
25
30
|
end
|
26
31
|
|
27
|
-
# Force initialization
|
32
|
+
# Force initialization.
|
28
33
|
Tribe.registry
|
34
|
+
Tribe.root
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tribe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chad Remesch
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-06-
|
11
|
+
date: 2013-06-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: workers
|
@@ -49,6 +49,7 @@ files:
|
|
49
49
|
- lib/tribe/future.rb
|
50
50
|
- lib/tribe/mailbox.rb
|
51
51
|
- lib/tribe/registry.rb
|
52
|
+
- lib/tribe/root.rb
|
52
53
|
- lib/tribe/safe_set.rb
|
53
54
|
- lib/tribe/version.rb
|
54
55
|
- tribe.gemspec
|