tribe 0.0.6 → 0.0.7
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/README.md +7 -8
- data/lib/tribe/actable.rb +80 -0
- data/lib/tribe/actor.rb +2 -81
- data/lib/tribe/mailbox.rb +11 -27
- data/lib/tribe/version.rb +1 -1
- data/lib/tribe.rb +4 -3
- data/tribe.gemspec +3 -3
- metadata +8 -5
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
# Tribe
|
2
2
|
|
3
|
-
Tribe is a Ruby gem that implements event driven actors.
|
4
|
-
Actors are
|
3
|
+
Tribe is a Ruby gem that implements event driven [actors] (http://en.wikipedia.org/wiki/Actor_model "actors").
|
4
|
+
Actors are lightweight concurrent objects that use asynchronous message passing for communication.
|
5
|
+
Tribe focuses on high performance, low latency, an easy to use API, and flexibility.
|
6
|
+
It is built on top of the [Workers] (https://github.com/chadrem/workers "Workers") gem, which allows it to support many actors (millions should be possible).
|
7
|
+
Actors can use a shared thread pool (default) or dedicted threads.
|
5
8
|
|
6
9
|
## Installation
|
7
10
|
|
@@ -51,7 +54,7 @@ Or install it yourself as:
|
|
51
54
|
MyActor.new(:name => "my_actor_#{i}")
|
52
55
|
end
|
53
56
|
|
54
|
-
# Send an event to each actors. Find each actor using the registry.
|
57
|
+
# Send an event to each actors. Find each actor using the global registry.
|
55
58
|
100.times do |i|
|
56
59
|
actor = Tribe.registry["my_actor_#{i}"]
|
57
60
|
actor.enqueue(:my_custom, 'hello world')
|
@@ -64,7 +67,7 @@ Or install it yourself as:
|
|
64
67
|
end
|
65
68
|
|
66
69
|
### Implementation notes
|
67
|
-
Because actors use a shared thread pool, it is important that they don't block for long periods of time.
|
70
|
+
Because actors use a shared thread pool, it is important that they don't block for long periods of time (short periods are fine).
|
68
71
|
Actors that block for long periods of time should use a dedicated thread (:dedicated => true or subclass from Tribe::DedicatedActor).
|
69
72
|
|
70
73
|
## Registries
|
@@ -104,7 +107,3 @@ In general you shouldn't have to create your own since there is a global one (Tr
|
|
104
107
|
3. Commit your changes (`git commit -am 'Added some feature'`)
|
105
108
|
4. Push to the branch (`git push origin my-new-feature`)
|
106
109
|
5. Create new Pull Request
|
107
|
-
|
108
|
-
## Copyright
|
109
|
-
|
110
|
-
Copyright (c) 2012 Chad Remesch. See LICENSE.txt for further details.
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Tribe
|
2
|
+
module Actable
|
3
|
+
include Workers::Helpers
|
4
|
+
|
5
|
+
def init_actable(options = {})
|
6
|
+
@logger = Workers::LogProxy.new(options[:logger])
|
7
|
+
@dedicated = options[:dedicated] || false
|
8
|
+
@mailbox = options[:mailbox] || Tribe::Mailbox.new
|
9
|
+
@registry = options[:registry] || Tribe.registry
|
10
|
+
@name = options[:name]
|
11
|
+
@pool = @dedicated ? Workers::Pool.new(:size => 1) : (options[:pool] || Workers.pool)
|
12
|
+
@alive = true
|
13
|
+
|
14
|
+
@registry.register(self)
|
15
|
+
end
|
16
|
+
|
17
|
+
def enqueue(command, data = nil)
|
18
|
+
return false unless alive?
|
19
|
+
|
20
|
+
@mailbox.push(Workers::Event.new(command, data)) do
|
21
|
+
@pool.perform { process_events }
|
22
|
+
end
|
23
|
+
|
24
|
+
return true
|
25
|
+
end
|
26
|
+
|
27
|
+
def alive?
|
28
|
+
@mailbox.synchronize { return @alive }
|
29
|
+
end
|
30
|
+
|
31
|
+
def name
|
32
|
+
return @name
|
33
|
+
end
|
34
|
+
|
35
|
+
def identifier
|
36
|
+
return @name ? "#{object_id}:#{@name}" : object_id
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def process_events
|
42
|
+
while (event = @mailbox.shift)
|
43
|
+
case event.command
|
44
|
+
when :shutdown
|
45
|
+
shutdown_handler(event)
|
46
|
+
@pool.shutdown if @dedicated
|
47
|
+
@mailbox.synchronize { @alive = false }
|
48
|
+
else
|
49
|
+
process_event(event)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
rescue Exception => e
|
54
|
+
@alive = false
|
55
|
+
exception_handler(e)
|
56
|
+
ensure
|
57
|
+
@mailbox.release do
|
58
|
+
@pool.perform { process_events }
|
59
|
+
end
|
60
|
+
|
61
|
+
return nil
|
62
|
+
end
|
63
|
+
|
64
|
+
#
|
65
|
+
# Subclass and override the below methods.
|
66
|
+
#
|
67
|
+
|
68
|
+
def process_event(event)
|
69
|
+
puts "Actor (#{identifier}) processing event (#{event.inspect}) using thread (#{Thread.current.object_id})."
|
70
|
+
end
|
71
|
+
|
72
|
+
def exception_handler(e)
|
73
|
+
puts concat_e("Actor (#{identifier}) died.", e)
|
74
|
+
end
|
75
|
+
|
76
|
+
def shutdown_handler(event)
|
77
|
+
puts "Actor (#{identifier}) is shutting down."
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/lib/tribe/actor.rb
CHANGED
@@ -1,88 +1,9 @@
|
|
1
1
|
module Tribe
|
2
2
|
class Actor
|
3
|
-
include
|
3
|
+
include Tribe::Actable
|
4
4
|
|
5
5
|
def initialize(options = {})
|
6
|
-
|
7
|
-
@dedicated = options[:dedicated] || false
|
8
|
-
@mailbox = options[:mailbox] || Tribe::Mailbox.new
|
9
|
-
@registry = options[:registry] || Tribe.registry
|
10
|
-
@name = options[:name]
|
11
|
-
@pool = @dedicated ? Workers::Pool.new(:size => 1) : (options[:pool] || Workers.pool)
|
12
|
-
@alive = true
|
13
|
-
|
14
|
-
@registry.register(self)
|
15
|
-
end
|
16
|
-
|
17
|
-
def enqueue(command, data = nil)
|
18
|
-
return false unless alive?
|
19
|
-
|
20
|
-
@mailbox.push(Workers::Event.new(command, data))
|
21
|
-
|
22
|
-
@pool.perform do
|
23
|
-
process_events
|
24
|
-
end
|
25
|
-
|
26
|
-
return true
|
27
|
-
end
|
28
|
-
|
29
|
-
def alive?
|
30
|
-
@mailbox.synchronize do
|
31
|
-
return @alive
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def name
|
36
|
-
return @name
|
37
|
-
end
|
38
|
-
|
39
|
-
def identifier
|
40
|
-
return @name ? "#{object_id}:#{@name}" : object_id
|
41
|
-
end
|
42
|
-
|
43
|
-
private
|
44
|
-
|
45
|
-
def process_events
|
46
|
-
while (event = @mailbox.shift)
|
47
|
-
case event.command
|
48
|
-
when :shutdown
|
49
|
-
shutdown_handler(event)
|
50
|
-
@pool.shutdown if @dedicated
|
51
|
-
@mailbox.synchronize do
|
52
|
-
@alive = false
|
53
|
-
end
|
54
|
-
else
|
55
|
-
process_event(event)
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
rescue Exception => e
|
60
|
-
@alive = false
|
61
|
-
exception_handler(e)
|
62
|
-
ensure
|
63
|
-
@mailbox.release do
|
64
|
-
@pool.perform do
|
65
|
-
process_events
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
return nil
|
70
|
-
end
|
71
|
-
|
72
|
-
#
|
73
|
-
# Subclass and override the below methods.
|
74
|
-
#
|
75
|
-
|
76
|
-
def process_event(event)
|
77
|
-
puts "Actor (#{identifier}) processing event (#{event.inspect}) using thread (#{Thread.current.object_id})."
|
78
|
-
end
|
79
|
-
|
80
|
-
def exception_handler(e)
|
81
|
-
puts concat_e("Actor (#{identifier}) died.", e)
|
82
|
-
end
|
83
|
-
|
84
|
-
def shutdown_handler(event)
|
85
|
-
puts "Actor (#{identifier}) is shutting down."
|
6
|
+
init_actable(options)
|
86
7
|
end
|
87
8
|
end
|
88
9
|
end
|
data/lib/tribe/mailbox.rb
CHANGED
@@ -5,10 +5,13 @@ module Tribe
|
|
5
5
|
@mutex = Mutex.new
|
6
6
|
end
|
7
7
|
|
8
|
-
def push(event)
|
8
|
+
def push(event, &block)
|
9
9
|
@mutex.synchronize do
|
10
10
|
@messages.push(event)
|
11
|
+
block.call unless @current_thread
|
11
12
|
end
|
13
|
+
|
14
|
+
return nil
|
12
15
|
end
|
13
16
|
|
14
17
|
def shift
|
@@ -17,44 +20,25 @@ module Tribe
|
|
17
20
|
|
18
21
|
@current_thread = Thread.current unless @current_thread
|
19
22
|
|
20
|
-
@messages.shift
|
23
|
+
return @messages.shift
|
21
24
|
end
|
22
25
|
end
|
23
26
|
|
24
|
-
def release(&
|
27
|
+
def release(&block)
|
25
28
|
@mutex.synchronize do
|
26
29
|
@current_thread = nil
|
27
|
-
|
28
|
-
if requeue_block && @messages.length > 0
|
29
|
-
requeue_block.call
|
30
|
-
end
|
30
|
+
block.call if block && @messages.length > 0
|
31
31
|
end
|
32
|
+
|
33
|
+
return nil
|
32
34
|
end
|
33
35
|
|
34
36
|
def synchronize(&block)
|
35
37
|
@mutex.synchronize do
|
36
38
|
block.call
|
37
39
|
end
|
38
|
-
end
|
39
|
-
|
40
|
-
# def obtain
|
41
|
-
# @mutex.synchronize do
|
42
|
-
# return false if @current_thread && @current_thread != Thread.current
|
43
40
|
|
44
|
-
|
45
|
-
|
46
|
-
# return true
|
47
|
-
# end
|
48
|
-
# end
|
49
|
-
|
50
|
-
# def release
|
51
|
-
# @mutex.synchronize do
|
52
|
-
# return false unless @current_thread && @current_thread == Thread.current
|
53
|
-
|
54
|
-
# @current_thread = nil
|
55
|
-
|
56
|
-
# return true
|
57
|
-
# end
|
58
|
-
# end
|
41
|
+
return nil
|
42
|
+
end
|
59
43
|
end
|
60
44
|
end
|
data/lib/tribe/version.rb
CHANGED
data/lib/tribe.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'workers'
|
2
2
|
|
3
3
|
require 'tribe/mailbox'
|
4
|
+
require 'tribe/actable'
|
4
5
|
require 'tribe/actor'
|
5
6
|
require 'tribe/dedicated_actor'
|
6
7
|
require 'tribe/registry'
|
@@ -8,12 +9,12 @@ require 'tribe/registry'
|
|
8
9
|
module Tribe
|
9
10
|
def self.registry
|
10
11
|
return @registry ||= Tribe::Registry.new
|
11
|
-
end
|
12
|
+
end
|
12
13
|
|
13
14
|
def self.registry=(val)
|
14
15
|
@registry.dispose if @registry
|
15
|
-
@registry = val
|
16
|
-
end
|
16
|
+
@registry = val
|
17
|
+
end
|
17
18
|
end
|
18
19
|
|
19
20
|
# Force initialization of defaults.
|
data/tribe.gemspec
CHANGED
@@ -4,9 +4,9 @@ require File.expand_path('../lib/tribe/version', __FILE__)
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.authors = ["Chad Remesch"]
|
6
6
|
gem.email = ["chad@remesch.com"]
|
7
|
-
gem.description = %q{
|
8
|
-
gem.summary = %q{
|
9
|
-
gem.homepage = ""
|
7
|
+
gem.description = %q{Tribe is a Ruby gem that implements event driven actors.}
|
8
|
+
gem.summary = %q{Actors are lightweight concurrent objects that use asynchronous message passing for communication. Tribe focuses on high performance, low latency, an easy to use API, and flexibility.}
|
9
|
+
gem.homepage = "https://github.com/chadrem/tribe"
|
10
10
|
|
11
11
|
gem.files = `git ls-files`.split($\)
|
12
12
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tribe
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.7
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-01-
|
12
|
+
date: 2013-01-26 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: workers
|
@@ -27,7 +27,7 @@ dependencies:
|
|
27
27
|
- - '='
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: 0.0.6
|
30
|
-
description:
|
30
|
+
description: Tribe is a Ruby gem that implements event driven actors.
|
31
31
|
email:
|
32
32
|
- chad@remesch.com
|
33
33
|
executables: []
|
@@ -41,13 +41,14 @@ files:
|
|
41
41
|
- README.md
|
42
42
|
- Rakefile
|
43
43
|
- lib/tribe.rb
|
44
|
+
- lib/tribe/actable.rb
|
44
45
|
- lib/tribe/actor.rb
|
45
46
|
- lib/tribe/dedicated_actor.rb
|
46
47
|
- lib/tribe/mailbox.rb
|
47
48
|
- lib/tribe/registry.rb
|
48
49
|
- lib/tribe/version.rb
|
49
50
|
- tribe.gemspec
|
50
|
-
homepage:
|
51
|
+
homepage: https://github.com/chadrem/tribe
|
51
52
|
licenses: []
|
52
53
|
post_install_message:
|
53
54
|
rdoc_options: []
|
@@ -70,5 +71,7 @@ rubyforge_project:
|
|
70
71
|
rubygems_version: 1.8.24
|
71
72
|
signing_key:
|
72
73
|
specification_version: 3
|
73
|
-
summary:
|
74
|
+
summary: Actors are lightweight concurrent objects that use asynchronous message passing
|
75
|
+
for communication. Tribe focuses on high performance, low latency, an easy to use
|
76
|
+
API, and flexibility.
|
74
77
|
test_files: []
|