foreign_actor 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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,16 @@
1
+ module ForeignActor
2
+
3
+ module Serializer
4
+ extend self
5
+
6
+ def pack(msg)
7
+ MessagePack.pack(msg)
8
+ end
9
+
10
+ def unpack(data)
11
+ MessagePack.unpack(data)
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -0,0 +1,3 @@
1
+ module ForeignWorker
2
+ VERSION = "0.0.1"
3
+ 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: []