foreign_actor 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +7 -0
- data/Gemfile +17 -0
- data/Guardfile +8 -0
- data/LICENSE +22 -0
- data/README.md +44 -0
- data/Rakefile +27 -0
- data/bin/device +75 -0
- data/bin/puppetmaster.rb +100 -0
- data/docs/design.graphml +221 -0
- data/docs/design.png +0 -0
- data/example/Procfile +2 -0
- data/example/client.rb +27 -0
- data/example/common.rb +10 -0
- data/example/device.yml +7 -0
- data/example/worker.rb +42 -0
- data/example2/Procfile +2 -0
- data/example2/README.md +9 -0
- data/example2/device.yml +4 -0
- data/example2/node.rb +59 -0
- data/foreign_actor.gemspec +20 -0
- data/lib/foreign_actor/client.rb +90 -0
- data/lib/foreign_actor/reactor.rb +275 -0
- data/lib/foreign_actor/reactor_mailbox.rb +29 -0
- data/lib/foreign_actor/serializer.rb +16 -0
- data/lib/foreign_actor/version.rb +3 -0
- data/lib/foreign_actor.rb +15 -0
- data/specs/spec_helper.rb +27 -0
- data/specs/unit/reactor_spec.rb +125 -0
- data/specs/unit/serializer_spec.rb +17 -0
- metadata +129 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
module ForeignActor
|
2
|
+
class ReactorMailbox < Celluloid::Mailbox
|
3
|
+
|
4
|
+
def initialize(*)
|
5
|
+
super
|
6
|
+
@actor = nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def <<(message)
|
10
|
+
super
|
11
|
+
if @actor
|
12
|
+
if message.is_a?(Celluloid::TerminationRequest)
|
13
|
+
@actor.subject.suspend_reactor('exit')
|
14
|
+
else
|
15
|
+
@actor.subject.suspend_reactor()
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def receive(timeout = nil, &block)
|
21
|
+
@actor ||= Thread.current[:actor]
|
22
|
+
if @messages.empty?
|
23
|
+
@actor.subject.wakeup_reactor()
|
24
|
+
end
|
25
|
+
super
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'ffi-rxs'
|
2
|
+
require 'celluloid'
|
3
|
+
|
4
|
+
require_relative 'foreign_actor/version'
|
5
|
+
|
6
|
+
require_relative 'foreign_actor/serializer'
|
7
|
+
|
8
|
+
require_relative 'foreign_actor/reactor_mailbox'
|
9
|
+
require_relative 'foreign_actor/reactor'
|
10
|
+
|
11
|
+
require_relative 'foreign_actor/client'
|
12
|
+
|
13
|
+
module ForeignActor
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler/setup'
|
3
|
+
|
4
|
+
# if ENV['COVERAGE']
|
5
|
+
# Bacon.allow_focused_run = false
|
6
|
+
|
7
|
+
# require 'simplecov'
|
8
|
+
# SimpleCov.start do
|
9
|
+
# add_filter ".*_spec"
|
10
|
+
# add_filter "/helpers/"
|
11
|
+
# end
|
12
|
+
|
13
|
+
# end
|
14
|
+
|
15
|
+
$LOAD_PATH.unshift( File.expand_path('../../lib' , __FILE__) )
|
16
|
+
require 'foreign_actor'
|
17
|
+
|
18
|
+
require 'rubygems'
|
19
|
+
require 'bundler/setup'
|
20
|
+
|
21
|
+
require 'eetee'
|
22
|
+
|
23
|
+
require 'eetee/ext/mocha'
|
24
|
+
require 'eetee/ext/time'
|
25
|
+
|
26
|
+
Thread.abort_on_exception = true
|
27
|
+
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe 'Reactor' do
|
4
|
+
before do
|
5
|
+
# @poller = stub('XS::Poller')
|
6
|
+
# @context = stub('XS::Context')
|
7
|
+
@timers = Timers.new
|
8
|
+
end
|
9
|
+
|
10
|
+
# should "initialize everything" do
|
11
|
+
# # create control sockets
|
12
|
+
# @ctrl = [stub('ServerCtrl'), stub('ClientCtrl')]
|
13
|
+
# @context.expects(:socket).with(XS::PAIR).returns(@ctrl[1])
|
14
|
+
# @context.expects(:socket).with(XS::PAIR).returns(@ctrl[0])
|
15
|
+
|
16
|
+
# @ctrl[0].expects(:bind)
|
17
|
+
# @ctrl[1].expects(:connect)
|
18
|
+
|
19
|
+
# @poller.expects(:register_readable).with(@ctrl[0])
|
20
|
+
|
21
|
+
# async_runner = stub('AsyncRunner', run: nil)
|
22
|
+
# ForeignActor::Reactor.any_instance.expects(:async).returns(async_runner)
|
23
|
+
|
24
|
+
# @reactor = ForeignActor::Reactor.new(@context, @poller, @timers)
|
25
|
+
# end
|
26
|
+
|
27
|
+
|
28
|
+
should 'start internal loop on create' do
|
29
|
+
ForeignActor::Reactor.any_instance.expects(:run)
|
30
|
+
@reactor = ForeignActor::Reactor.new(nil, nil, @timers)
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'messages handling' do
|
34
|
+
before do
|
35
|
+
ForeignActor::InternalReactor.any_instance.stubs(:async)
|
36
|
+
@reactor = ForeignActor::InternalReactor.new(nil, nil, @timers)
|
37
|
+
@socket = stub('Socket')
|
38
|
+
@ctrl_msgs = @reactor.instance_variable_get('@control_messages')
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
should 'suspend reactor loop when asked' do
|
43
|
+
@reactor.expects(:control_socket?).with(@socket).returns(true)
|
44
|
+
@reactor.expects(:wait)
|
45
|
+
@ctrl_msgs << 'suspend'
|
46
|
+
@reactor.send(:handle_message, @socket, [''])
|
47
|
+
end
|
48
|
+
|
49
|
+
should 'terminate reactor loop when asked' do
|
50
|
+
@reactor.expects(:control_socket?).with(@socket).returns(true)
|
51
|
+
@reactor.expects(:signal).with(:exit_confirmed)
|
52
|
+
|
53
|
+
@ctrl_msgs << 'exit'
|
54
|
+
->{
|
55
|
+
@reactor.send(:handle_message, @socket, [''])
|
56
|
+
}.should.raise(ForeignActor::Reactor::StopLoop)
|
57
|
+
end
|
58
|
+
|
59
|
+
should 'execute synchronous calls' do
|
60
|
+
server = stub('Server')
|
61
|
+
@reactor.send(:register_server, @socket, server)
|
62
|
+
|
63
|
+
msg = ['routing_id', '', MessagePack.pack(
|
64
|
+
task_id: 'a23', type: 'sync_call', method: 'add', arguments: [1, 4]
|
65
|
+
)]
|
66
|
+
|
67
|
+
expected_response = ['routing_id', '', MessagePack.pack(
|
68
|
+
task_id: 'a23', type: 'response', ret: 5
|
69
|
+
)]
|
70
|
+
|
71
|
+
server.expects(:add).with(1, 4).returns(5)
|
72
|
+
|
73
|
+
@reactor.expects(:send_msg).with(@socket, *expected_response)
|
74
|
+
@reactor.send(:handle_message, @socket, msg)
|
75
|
+
end
|
76
|
+
|
77
|
+
should 'execute asynchronous calls' do
|
78
|
+
server = stub('Server')
|
79
|
+
@reactor.send(:register_server, @socket, server)
|
80
|
+
|
81
|
+
msg = ['routing_id', '', MessagePack.pack(
|
82
|
+
task_id: 'a23', type: 'async_call', method: 'add', arguments: [1, 4]
|
83
|
+
)]
|
84
|
+
|
85
|
+
server.expects(:async).with('add', 1, 4).returns(5)
|
86
|
+
|
87
|
+
@reactor.send(:handle_message, @socket, msg)
|
88
|
+
end
|
89
|
+
|
90
|
+
should 'call wake up task when a response is received' do
|
91
|
+
task = stub('Task', :running? => true)
|
92
|
+
@reactor.instance_variable_get('@waiting_readables')[@socket] = {'a23' => task}
|
93
|
+
|
94
|
+
msg = ['routing_id', '', MessagePack.pack(
|
95
|
+
task_id: 'a23', type: 'response', ret: 5
|
96
|
+
)]
|
97
|
+
|
98
|
+
task.expects(:resume).with(5)
|
99
|
+
|
100
|
+
@reactor.send(:handle_message, @socket, msg)
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
describe 'run loop' do
|
106
|
+
before do
|
107
|
+
ForeignActor::InternalReactor.any_instance.stubs(:async)
|
108
|
+
@reactor = ForeignActor::InternalReactor.new(nil, nil, @timers)
|
109
|
+
end
|
110
|
+
|
111
|
+
should 'fire timers on start' do
|
112
|
+
@timers.expects(:fire)
|
113
|
+
@reactor.run_once(false)
|
114
|
+
end
|
115
|
+
|
116
|
+
should 'not wait indefinitely if timers need to be fired' do
|
117
|
+
@timers.expects(:wait_interval).twice.returns(0.1)
|
118
|
+
|
119
|
+
elapsed = time_block { @reactor.run_once }
|
120
|
+
# 100 ms with a 2ms erro margin
|
121
|
+
elapsed.should.be.close?(100, 2)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
2
|
+
|
3
|
+
describe 'MessageSerializer' do
|
4
|
+
before do
|
5
|
+
@serializer = ForeignActor::Serializer
|
6
|
+
@data = {"attr1" => 45, "arr" => [1, 2, "dog"]}
|
7
|
+
end
|
8
|
+
|
9
|
+
should 'pack data with MessagePack' do
|
10
|
+
@serializer.pack(@data).should == MessagePack.pack(@data)
|
11
|
+
end
|
12
|
+
|
13
|
+
should 'unpack data with MessagePack' do
|
14
|
+
@serializer.unpack(MessagePack.pack(@data)).should == @data
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: foreign_actor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Julien Ammous
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-11-18 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: ffi-rxs
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.2.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 1.2.1
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: celluloid
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - '='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 0.12.3
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - '='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 0.12.3
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: msgpack
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - '='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 0.4.7
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.4.7
|
62
|
+
description: Distributed Actors above Celluloid
|
63
|
+
email:
|
64
|
+
- schmurfy@gmail.com
|
65
|
+
executables:
|
66
|
+
- device
|
67
|
+
extensions: []
|
68
|
+
extra_rdoc_files: []
|
69
|
+
files:
|
70
|
+
- .gitignore
|
71
|
+
- Gemfile
|
72
|
+
- Guardfile
|
73
|
+
- LICENSE
|
74
|
+
- README.md
|
75
|
+
- Rakefile
|
76
|
+
- bin/device
|
77
|
+
- bin/puppetmaster.rb
|
78
|
+
- docs/design.graphml
|
79
|
+
- docs/design.png
|
80
|
+
- example/Procfile
|
81
|
+
- example/client.rb
|
82
|
+
- example/common.rb
|
83
|
+
- example/device.yml
|
84
|
+
- example/worker.rb
|
85
|
+
- example2/Procfile
|
86
|
+
- example2/README.md
|
87
|
+
- example2/device.yml
|
88
|
+
- example2/node.rb
|
89
|
+
- foreign_actor.gemspec
|
90
|
+
- lib/foreign_actor.rb
|
91
|
+
- lib/foreign_actor/client.rb
|
92
|
+
- lib/foreign_actor/reactor.rb
|
93
|
+
- lib/foreign_actor/reactor_mailbox.rb
|
94
|
+
- lib/foreign_actor/serializer.rb
|
95
|
+
- lib/foreign_actor/version.rb
|
96
|
+
- specs/spec_helper.rb
|
97
|
+
- specs/unit/reactor_spec.rb
|
98
|
+
- specs/unit/serializer_spec.rb
|
99
|
+
homepage: ''
|
100
|
+
licenses: []
|
101
|
+
post_install_message:
|
102
|
+
rdoc_options: []
|
103
|
+
require_paths:
|
104
|
+
- lib
|
105
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
segments:
|
112
|
+
- 0
|
113
|
+
hash: 2556761358232140633
|
114
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
|
+
none: false
|
116
|
+
requirements:
|
117
|
+
- - ! '>='
|
118
|
+
- !ruby/object:Gem::Version
|
119
|
+
version: '0'
|
120
|
+
segments:
|
121
|
+
- 0
|
122
|
+
hash: 2556761358232140633
|
123
|
+
requirements: []
|
124
|
+
rubyforge_project:
|
125
|
+
rubygems_version: 1.8.24
|
126
|
+
signing_key:
|
127
|
+
specification_version: 3
|
128
|
+
summary: Distributed Actors
|
129
|
+
test_files: []
|