foreign_actor 0.0.1

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.
@@ -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: []