foreign_actor 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 55a8cb1bd967272cd69175d48bf7a2750d19fdb0
4
+ data.tar.gz: d6dc116fde6c0da3ff56db9d5d500de80fce65ac
5
+ SHA512:
6
+ metadata.gz: 483148ed774ac5a281bc359b84fc5c627f42b2e4064c6a60e0d738efdd65df7bee5d2680ed5327339760ab62a9e6b63e988eac4d57589809085221eb8e4dc1aa
7
+ data.tar.gz: 66aa30bda494c00cf099d64a4caae9abe7f134eb7e5af8099cf35a973f55d6caf60ecfd30fca7e6782838e1c9bc10b75da42afa4da83f20e7c21036ed73b6a30
data/Gemfile CHANGED
@@ -3,12 +3,15 @@ source 'https://rubygems.org'
3
3
  gemspec
4
4
 
5
5
  gem 'rake'
6
- gem 'celluloid', git: 'git://github.com/celluloid/celluloid.git'
6
+
7
+ group(:doc) do
8
+ gem 'tilt'
9
+ end
7
10
 
8
11
  group(:test) do
9
- gem 'eetee', '= 0.0.1'
12
+ gem 'eetee', '~> 0.0.6'
10
13
  gem 'mocha', '~> 0.12.0'
11
- gem 'factory_girl'
14
+ # gem 'factory_girl'
12
15
 
13
16
  gem 'simplecov'
14
17
  gem 'guard', '~> 1.5.4'
data/README.md CHANGED
@@ -6,22 +6,19 @@ in multiple processes/machines, the idea is to be able to move an actor to anoth
6
6
 
7
7
 
8
8
  # How ?
9
- I used the Crossroads library (zeromq fork) to achieve my goal using XREQ/XREP sockets, this allows multiple clients with multiple workers, each clients being able to make calls with
10
- or without a return value.
9
+ I used the Crossroads library to achieve my goal using XREQ/XREP sockets, this allows multiple clients with multiple workers each clients being able to make calls with or without a return value.
11
10
 
12
11
  Here is what it looks like:
13
- ![](docs/design.png "Architecture")
12
+ ![](https://raw.github.com/schmurfy/foreign_actor/master/docs/design.png "Architecture")
14
13
 
15
14
  In this picture the square boxes are processes while the rounded box are the services (actors).
16
- In a standard client/server interaction one client connects to one or more server and to do so
17
- needs to know the addresses of all of them, in my case the device process is here to simplify this: both clients and workers connects to it which allows as a direct result things like adding
18
- a worker in live, you just start it, it connects to the device and it can starts to process requests immediately.
19
- Something to note is that each of these processes can run on a different physical machine
20
- allowing effectively to distribute jobs on multiple cores as well as multiple machines.
15
+ In a standard client/server interaction one client connects to one or more server and to do so needs to know the addresses of all of them, in our case the router process is here to simplify this: both clients and workers connects to it which allows as a direct result things like adding
16
+ a worker in live, you just start it, it connects to the router and it can starts processing requests immediately.
17
+ Something to note is that each of these processes can run on a different physical machine allowing effectively to distribute jobs on multiple cores as well as multiple machines.
21
18
 
22
19
 
23
20
  # Constraints
24
- Since the arguments to the actions are serialized using MessagePack they need to be serializable by it, which means that you can only send basic types to a foreign actor but messagepack allows everything you need really:
21
+ The methods arguments are serialized using MessagePack so obviously they need to be serializable by it, which means that you can only send "basic types" to a foreign actor, do not fear though since messagepack allows everything you need:
25
22
  - Integers
26
23
  - Floats (ex: 2.34)
27
24
  - Strings (ex: "a cat")
@@ -30,15 +27,131 @@ Since the arguments to the actions are serialized using MessagePack they need to
30
27
  - Nil
31
28
  - Array (ex: [1, "a cat", {"a" : nil}])
32
29
 
33
- Why not going with Marshal ? Because I don't want to close the door to another language, you
34
- can well imagine calling a service which is in fact provided bya C server, a python server or
35
- anything else, I just see no reason to close that door.
30
+ Why not going with Marshal ? Because I don't want to close the door to another language, you can well imagine calling a service which is in fact provided bya C server, a python server or anything else, I just saw no reason to close that door.
31
+ Another problem I have with Marshal is that the format could well change in a future ruby version which would force users to switch both the server and the client at the same time.
36
32
 
37
33
 
38
34
  # Examples
39
- You can look at the example and example2 folder.
35
+ You can look at the example and example2 folder but here is the code of example1:
40
36
 
37
+ ## Client
38
+
39
+ ```ruby
40
+ require 'rubygems'
41
+ require 'bundler/setup'
42
+
43
+ require 'foreign_actor'
44
+
45
+ # disable buffering to see our logs with foreman
46
+ $stdout.sync = true
47
+
48
+ # Here we create a supervision group to start the reactor which
49
+ # is an actor specific to foreign_actor and which is required.
50
+ # The reactor need to be named since the client will access
51
+ # it by its name which is :xs_reactor by default.
52
+ class ClientGroup < Celluloid::SupervisionGroup
53
+ supervise ForeignActor::Reactor, :as => :xs_reactor
54
+
55
+ end
56
+
57
+ ClientGroup.run!
58
+
59
+ # we create the "client" and give it the address to connect
60
+ # to (defined in router.yml as the front address)
61
+ cl = ForeignActor::Client.new('tcp://127.0.0.1:7000')
62
+
63
+ # and now we have standard celluloid code which
64
+ # does what you would expect.
65
+
66
+ # run an async task
67
+ cl.async.do_it(0)
68
+
69
+ loop do
70
+ f = []
71
+
72
+ # run a synchronous task and display the result
73
+ p cl.do_it(2)
74
+
75
+ # use future to run 4 tasks in parallel
76
+ # and display their results
77
+ started_at = Time.now
78
+ 4.times {|n| f << cl.future.do_it(n) }
79
+
80
+ p f.map(&:value)
81
+
82
+ elapsed = (Time.now - started_at)
83
+ puts "time: #{elapsed} seconds"
84
+ end
85
+ ```
86
+
87
+ ## Server
88
+
89
+ ```ruby
90
+ require 'rubygems'
91
+ require 'bundler/setup'
92
+
93
+ require 'foreign_actor'
94
+
95
+ # disable buffering to see our logs with foreman
96
+ $stdout.sync = true
97
+
98
+ class Worker
99
+ include Celluloid
100
+
101
+ def initialize(endpoint)
102
+ # register this actor as a worker, this allows the actor to
103
+ # handle requested received on this endpoint (defined in
104
+ # router.yml as the back address)
105
+ Actor[:xs_reactor].serve_actor!(endpoint, Actor.current)
106
+ end
107
+
108
+ def do_it(n)
109
+ # force the process to sleep, we do not wait
110
+ # to use the celluloid sleep here
111
+ Kernel.sleep 1
112
+
113
+ "response #{$$}"
114
+ end
115
+
116
+ end
117
+
118
+ # define our reactor actor and our worker, we pass it the endpoint
119
+ # to connect to but you may well hardcode above or pass it anyway
120
+ # you like.
121
+ class RootGroup < Celluloid::SupervisionGroup
122
+ supervise ForeignActor::Reactor, :as => :xs_reactor
123
+ supervise Worker, :as => :worker1, args: ['tcp://127.0.0.1:7001']
124
+
125
+ end
126
+
127
+ RootGroup.run!
128
+
129
+ puts "Worker started."
130
+
131
+ trap("INT") { Celluloid.shutdown; exit }
132
+ sleep
133
+ ```
134
+
135
+ ## Router configuration
136
+
137
+ ```yaml
138
+ endpoint1:
139
+ front: 'tcp://*:7000'
140
+ back: 'tcp://*:7001'
141
+
142
+ ```
143
+
144
+ You then run the client and server as normal:
145
+ ```bash
146
+ ruby client.rb
147
+ ruby worker.rb
148
+ ```
149
+
150
+ And you need a router:
151
+ ```bash
152
+ # by default the router.yml file in the current directory will
153
+ # be used if none specified
154
+ bundle exec router router.yml
155
+ ```
41
156
 
42
- # TODO
43
- - handle workers crash better, the client should be informed instead of waiting for a timeout.
44
157
 
data/README.md.erb ADDED
@@ -0,0 +1,68 @@
1
+ # What is this ?
2
+
3
+ I wanted to combine two great libraries for concurrent work: Crossroads (zeromq fork) and Celluloid.
4
+ Foreign Actor is my attempt at building a simple way to distribute celluloid actors
5
+ in multiple processes/machines, the idea is to be able to move an actor to another process with no change to the actor itself and minimal changes on the server and client side code.
6
+
7
+
8
+ # How ?
9
+ I used the Crossroads library to achieve my goal using XREQ/XREP sockets, this allows multiple clients with multiple workers each clients being able to make calls with or without a return value.
10
+
11
+ Here is what it looks like:
12
+ ![](https://raw.github.com/schmurfy/foreign_actor/master/docs/design.png "Architecture")
13
+
14
+ In this picture the square boxes are processes while the rounded box are the services (actors).
15
+ In a standard client/server interaction one client connects to one or more server and to do so needs to know the addresses of all of them, in our case the router process is here to simplify this: both clients and workers connects to it which allows as a direct result things like adding
16
+ a worker in live, you just start it, it connects to the router and it can starts processing requests immediately.
17
+ Something to note is that each of these processes can run on a different physical machine allowing effectively to distribute jobs on multiple cores as well as multiple machines.
18
+
19
+
20
+ # Constraints
21
+ The methods arguments are serialized using MessagePack so obviously they need to be serializable by it, which means that you can only send "basic types" to a foreign actor, do not fear though since messagepack allows everything you need:
22
+ - Integers
23
+ - Floats (ex: 2.34)
24
+ - Strings (ex: "a cat")
25
+ - Hash
26
+ - Boolean
27
+ - Nil
28
+ - Array (ex: [1, "a cat", {"a" : nil}])
29
+
30
+ Why not going with Marshal ? Because I don't want to close the door to another language, you can well imagine calling a service which is in fact provided bya C server, a python server or anything else, I just saw no reason to close that door.
31
+ Another problem I have with Marshal is that the format could well change in a future ruby version which would force users to switch both the server and the client at the same time.
32
+
33
+
34
+ # Examples
35
+ You can look at the example and example2 folder but here is the code of example1:
36
+
37
+ ## Client
38
+
39
+ ```ruby
40
+ <%= File.read('example/client.rb') %>
41
+ ```
42
+
43
+ ## Server
44
+
45
+ ```ruby
46
+ <%= File.read('example/worker.rb') %>
47
+ ```
48
+
49
+ ## Router configuration
50
+
51
+ ```yaml
52
+ <%= File.read('example/router.yml') %>
53
+ ```
54
+
55
+ You then run the client and server as normal:
56
+ ```bash
57
+ ruby client.rb
58
+ ruby worker.rb
59
+ ```
60
+
61
+ And you need a router:
62
+ ```bash
63
+ # by default the router.yml file in the current directory will
64
+ # be used if none specified
65
+ bundle exec router router.yml
66
+ ```
67
+
68
+
data/Rakefile CHANGED
@@ -4,6 +4,13 @@ require "bundler/gem_tasks"
4
4
 
5
5
  task :default => :test
6
6
 
7
+ task :readme do
8
+ require 'tilt'
9
+ tmpl = Tilt::ERBTemplate.new(File.expand_path('../README.md.erb', __FILE__))
10
+ out = tmpl.render(nil)
11
+ File.write(File.expand_path('../README.md', __FILE__), out)
12
+ end
13
+
7
14
  task :test do
8
15
 
9
16
  # do not generate coverage report under travis
data/TODO.todo ADDED
@@ -0,0 +1,2 @@
1
+
2
+ - handle workers crash better, the client should be informed instead of waiting for a timeout.
@@ -9,7 +9,7 @@ poller = XS::Poller.new
9
9
  path = nil
10
10
 
11
11
  if ARGV.size == 0
12
- path = 'device.yml'
12
+ path = 'router.yml'
13
13
  elsif ARGV
14
14
  path = ARGV[0]
15
15
  end
data/docs/design.graphml CHANGED
@@ -15,7 +15,6 @@
15
15
  <graph edgedefault="directed" id="G">
16
16
  <data key="d7"/>
17
17
  <node id="n0">
18
- <data key="d5"/>
19
18
  <data key="d6">
20
19
  <y:ShapeNode>
21
20
  <y:Geometry height="26.0" width="92.0" x="590.0" y="489.0"/>
@@ -27,7 +26,6 @@
27
26
  </data>
28
27
  </node>
29
28
  <node id="n1">
30
- <data key="d5"/>
31
29
  <data key="d6">
32
30
  <y:ShapeNode>
33
31
  <y:Geometry height="120.0" width="122.0" x="579.0" y="477.0"/>
@@ -39,19 +37,17 @@
39
37
  </data>
40
38
  </node>
41
39
  <node id="n2">
42
- <data key="d5"/>
43
40
  <data key="d6">
44
41
  <y:ShapeNode>
45
42
  <y:Geometry height="41.0" width="109.0" x="495.0" y="390.0"/>
46
43
  <y:Fill hasColor="false" transparent="false"/>
47
44
  <y:BorderStyle color="#000000" type="line" width="2.0"/>
48
- <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="internal" modelPosition="c" textColor="#000000" visible="true" width="42.185546875" x="33.4072265625" y="11.43359375">Device</y:NodeLabel>
45
+ <y:NodeLabel alignment="center" autoSizePolicy="content" fontFamily="Dialog" fontSize="12" fontStyle="plain" hasBackgroundColor="false" hasLineColor="false" height="18.1328125" modelName="internal" modelPosition="c" textColor="#000000" visible="true" width="42.490234375" x="33.2548828125" y="11.43359375">Router</y:NodeLabel>
49
46
  <y:Shape type="rectangle"/>
50
47
  </y:ShapeNode>
51
48
  </data>
52
49
  </node>
53
50
  <node id="n3">
54
- <data key="d5"/>
55
51
  <data key="d6">
56
52
  <y:ShapeNode>
57
53
  <y:Geometry height="60.0" width="74.0" x="327.0" y="240.0"/>
@@ -63,7 +59,6 @@
63
59
  </data>
64
60
  </node>
65
61
  <node id="n4">
66
- <data key="d5"/>
67
62
  <data key="d6">
68
63
  <y:ShapeNode>
69
64
  <y:Geometry height="60.0" width="74.0" x="452.0" y="240.0"/>
@@ -75,7 +70,6 @@
75
70
  </data>
76
71
  </node>
77
72
  <node id="n5">
78
- <data key="d5"/>
79
73
  <data key="d6">
80
74
  <y:ShapeNode>
81
75
  <y:Geometry height="60.0" width="74.0" x="577.0" y="240.0"/>
@@ -87,7 +81,6 @@
87
81
  </data>
88
82
  </node>
89
83
  <node id="n6">
90
- <data key="d5"/>
91
84
  <data key="d6">
92
85
  <y:ShapeNode>
93
86
  <y:Geometry height="60.0" width="74.0" x="702.0" y="240.0"/>
@@ -99,7 +92,6 @@
99
92
  </data>
100
93
  </node>
101
94
  <node id="n7">
102
- <data key="d5"/>
103
95
  <data key="d6">
104
96
  <y:ShapeNode>
105
97
  <y:Geometry height="26.0" width="92.0" x="416.0" y="529.0"/>
@@ -111,7 +103,6 @@
111
103
  </data>
112
104
  </node>
113
105
  <node id="n8">
114
- <data key="d5"/>
115
106
  <data key="d6">
116
107
  <y:ShapeNode>
117
108
  <y:Geometry height="26.0" width="92.0" x="416.0" y="489.0"/>
@@ -123,7 +114,6 @@
123
114
  </data>
124
115
  </node>
125
116
  <node id="n9">
126
- <data key="d5"/>
127
117
  <data key="d6">
128
118
  <y:ShapeNode>
129
119
  <y:Geometry height="120.0" width="122.0" x="405.0" y="477.0"/>
data/docs/design.png CHANGED
Binary file
data/example/Procfile CHANGED
@@ -1,2 +1,2 @@
1
- master: ruby ../bin/device
1
+ master: ruby ../bin/router
2
2
  worker: ruby worker.rb
data/example/client.rb CHANGED
@@ -1,5 +1,15 @@
1
- require_relative 'common'
1
+ require 'rubygems'
2
+ require 'bundler/setup'
2
3
 
4
+ require 'foreign_actor'
5
+
6
+ # disable buffering to see our logs with foreman
7
+ $stdout.sync = true
8
+
9
+ # Here we create a supervision group to start the reactor which
10
+ # is an actor specific to foreign_actor and which is required.
11
+ # The reactor need to be named since the client will access
12
+ # it by its name which is :xs_reactor by default.
3
13
  class ClientGroup < Celluloid::SupervisionGroup
4
14
  supervise ForeignActor::Reactor, :as => :xs_reactor
5
15
 
@@ -7,16 +17,24 @@ end
7
17
 
8
18
  ClientGroup.run!
9
19
 
10
- # cl = ForeignActor::Client.create(CLIENT_ENDPOINT)
11
- cl = ForeignActor::Client.new(CLIENT_ENDPOINT)
20
+ # we create the "client" and give it the address to connect
21
+ # to (defined in router.yml as the front address)
22
+ cl = ForeignActor::Client.new('tcp://127.0.0.1:7000')
23
+
24
+ # and now we have standard celluloid code which
25
+ # does what you would expect.
12
26
 
27
+ # run an async task
13
28
  cl.async.do_it(0)
14
29
 
15
30
  loop do
16
31
  f = []
17
32
 
33
+ # run a synchronous task and display the result
18
34
  p cl.do_it(2)
19
35
 
36
+ # use future to run 4 tasks in parallel
37
+ # and display their results
20
38
  started_at = Time.now
21
39
  4.times {|n| f << cl.future.do_it(n) }
22
40
 
File without changes
data/example/worker.rb CHANGED
@@ -1,42 +1,42 @@
1
- require_relative 'common'
1
+ require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
+ require 'foreign_actor'
5
+
6
+ # disable buffering to see our logs with foreman
7
+ $stdout.sync = true
2
8
 
3
9
  class Worker
4
10
  include Celluloid
5
11
 
6
12
  def initialize(endpoint)
7
- Actor[:xs_reactor].serve_actor!(endpoint, Actor.current)
13
+ # register this actor as a worker, this allows the actor to
14
+ # handle requested received on this endpoint (defined in
15
+ # router.yml as the back address)
16
+ Actor[:xs_reactor].async.serve_actor(endpoint, Actor.current)
8
17
  end
9
18
 
10
19
  def do_it(n)
11
- # if n == 2
12
- # raise "what ?"
13
- # end
14
-
20
+ # force the process to sleep, we do not wait
21
+ # to use the celluloid sleep here
15
22
  Kernel.sleep 1
16
23
 
17
- # if n == 0
18
- # puts "did it !"
19
- # end
20
-
21
- "toto #{$$}"
24
+ "response #{$$}"
22
25
  end
23
26
 
24
27
  end
25
28
 
29
+ # define our reactor actor and our worker, we pass it the endpoint
30
+ # to connect to but you may well hardcode above or pass it anyway
31
+ # you like.
26
32
  class RootGroup < Celluloid::SupervisionGroup
27
33
  supervise ForeignActor::Reactor, :as => :xs_reactor
28
- # supervise ForeignActor::WorkersSupervisor
29
- supervise Worker, :as => :worker1, args: [WORKERS_ENDPOINT]
34
+ supervise Worker, :as => :worker1, args: ['tcp://127.0.0.1:7001']
30
35
 
31
36
  end
32
37
 
33
38
  RootGroup.run!
34
39
 
35
- # Celluloid::Actor[:workers].register_server(:worker1, Worker, WORKERS_ENDPOINT)
36
-
37
- # Celluloid::Actor[:xs_reactor].serve_actor(WORKERS_ENDPOINT, Worker.new)
38
-
39
40
  puts "Worker started."
40
41
 
41
- trap("INT") { Celluloid.shutdown; exit }
42
42
  sleep
data/example2/Procfile CHANGED
@@ -1,2 +1,2 @@
1
- master: ruby ../bin/device
1
+ master: ruby ../bin/router
2
2
  node: ruby node.rb
data/example2/node.rb CHANGED
@@ -14,7 +14,7 @@ class Worker
14
14
  include Celluloid
15
15
 
16
16
  def initialize(endpoint)
17
- Actor[:xs_reactor].serve_actor!(endpoint, Actor.current)
17
+ Actor[:xs_reactor].async.serve_actor(endpoint, Actor.current)
18
18
  end
19
19
 
20
20
  def handle_it(token)
@@ -36,7 +36,6 @@ end
36
36
  RootGroup.run!
37
37
 
38
38
  puts "Node #{node_id} started."
39
- trap("INT") { Celluloid.shutdown; exit }
40
39
 
41
40
  cl = ForeignActor::Client.new(CLIENT_ENDPOINT, 4)
42
41
 
@@ -2,6 +2,3 @@ endpoint1:
2
2
  front: 'tcp://*:7000'
3
3
  back: 'tcp://*:7001'
4
4
 
5
- endpoint2:
6
- front: 'tcp://*:7002'
7
- back: 'tcp://*:7003'
@@ -9,12 +9,12 @@ Gem::Specification.new do |gem|
9
9
  gem.homepage = ""
10
10
 
11
11
  gem.files = `git ls-files`.split($\)
12
- gem.executables = ['device']
12
+ gem.executables = ['router']
13
13
  gem.name = "foreign_actor"
14
14
  gem.require_paths = ["lib"]
15
15
  gem.version = ForeignWorker::VERSION
16
16
 
17
17
  gem.add_dependency 'ffi-rxs', '~> 1.2.1'
18
- gem.add_dependency 'celluloid', '= 0.12.3'
19
- gem.add_dependency 'msgpack', '= 0.4.7'
18
+ gem.add_dependency 'celluloid', '~> 0.14.0'
19
+ gem.add_dependency 'msgpack', '~> 0.5.4'
20
20
  end
@@ -5,7 +5,7 @@ module ForeignActor
5
5
  State = Struct.new(:state) do
6
6
  attr_accessor :state
7
7
  end
8
-
8
+
9
9
  class ClientProxy < Celluloid::ActorProxy
10
10
  class MethodMissingRedirector
11
11
  def initialize(&block)
@@ -38,23 +38,27 @@ module ForeignActor
38
38
  end
39
39
 
40
40
  def method_missing(meth, *args, &block)
41
- # bang methods are async calls
42
- type = :sync
43
- if meth.match(/!$/)
44
- meth = meth.to_s
45
- meth.slice!(-1, 1)
46
- type = :async
41
+ if (meth == :__send__) && (args[0] == :initialize)
42
+ super
43
+ else
44
+ # bang methods are async calls
45
+ async = false
46
+ if meth.match(/!$/)
47
+ meth = meth.to_s
48
+ meth.slice!(-1, 1)
49
+ async = true
50
+ end
51
+
52
+ do_call(async, meth, args)
47
53
  end
48
-
49
- do_call(type, meth, args)
50
54
  end
51
-
55
+
52
56
  private
53
57
  def do_call(type, meth, args)
54
58
  case type
55
- when :async then Celluloid::Actor.async(@mailbox, :async_remote_request, meth, *args)
56
- when :sync then Celluloid::Actor.call(@mailbox, :sync_remote_request, meth, *args)
57
- when :future then Celluloid::Actor.future(@mailbox, :sync_remote_request, meth, *args)
59
+ when :async then ::Celluloid::Actor.async(@mailbox, :async_remote_request, meth, *args)
60
+ when :sync then ::Celluloid::Actor.call(@mailbox, :sync_remote_request, meth, *args)
61
+ when :future then ::Celluloid::Actor.future(@mailbox, :sync_remote_request, meth, *args)
58
62
  end
59
63
  end
60
64
 
@@ -25,7 +25,6 @@ module ForeignActor
25
25
 
26
26
  @poller.register_readable(@control_socket_srv)
27
27
 
28
- async(:run)
29
28
  end
30
29
 
31
30
 
@@ -269,6 +268,10 @@ module ForeignActor
269
268
  include Celluloid
270
269
  mailbox_class ReactorMailbox
271
270
 
271
+ def initialize(*)
272
+ super
273
+ async.run()
274
+ end
272
275
  end
273
276
 
274
277
 
@@ -18,7 +18,7 @@ module ForeignActor
18
18
  end
19
19
 
20
20
  def receive(timeout = nil, &block)
21
- @actor ||= Thread.current[:actor]
21
+ @actor ||= Thread.current[:celluloid_actor]
22
22
  if @messages.empty?
23
23
  @actor.subject.wakeup_reactor()
24
24
  end
@@ -1,3 +1,3 @@
1
1
  module ForeignWorker
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/specs/spec_helper.rb CHANGED
@@ -25,3 +25,4 @@ require 'eetee/ext/time'
25
25
 
26
26
  Thread.abort_on_exception = true
27
27
 
28
+ require 'celluloid/autostart'
@@ -28,6 +28,7 @@ describe 'Reactor' do
28
28
  should 'start internal loop on create' do
29
29
  ForeignActor::Reactor.any_instance.expects(:run)
30
30
  @reactor = ForeignActor::Reactor.new(nil, nil, @timers)
31
+ sleep(0.01)
31
32
  end
32
33
 
33
34
  describe 'messages handling' do
metadata CHANGED
@@ -1,20 +1,18 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: foreign_actor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
5
- prerelease:
4
+ version: 0.0.2
6
5
  platform: ruby
7
6
  authors:
8
7
  - Julien Ammous
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2012-11-18 00:00:00.000000000 Z
11
+ date: 2013-05-11 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: ffi-rxs
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
17
  - - ~>
20
18
  - !ruby/object:Gem::Version
@@ -22,7 +20,6 @@ dependencies:
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
24
  - - ~>
28
25
  - !ruby/object:Gem::Version
@@ -30,40 +27,36 @@ dependencies:
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: celluloid
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - '='
31
+ - - ~>
36
32
  - !ruby/object:Gem::Version
37
- version: 0.12.3
33
+ version: 0.14.0
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - '='
38
+ - - ~>
44
39
  - !ruby/object:Gem::Version
45
- version: 0.12.3
40
+ version: 0.14.0
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: msgpack
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - '='
45
+ - - ~>
52
46
  - !ruby/object:Gem::Version
53
- version: 0.4.7
47
+ version: 0.5.4
54
48
  type: :runtime
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - '='
52
+ - - ~>
60
53
  - !ruby/object:Gem::Version
61
- version: 0.4.7
54
+ version: 0.5.4
62
55
  description: Distributed Actors above Celluloid
63
56
  email:
64
57
  - schmurfy@gmail.com
65
58
  executables:
66
- - device
59
+ - router
67
60
  extensions: []
68
61
  extra_rdoc_files: []
69
62
  files:
@@ -72,20 +65,22 @@ files:
72
65
  - Guardfile
73
66
  - LICENSE
74
67
  - README.md
68
+ - README.md.erb
75
69
  - Rakefile
76
- - bin/device
70
+ - TODO.todo
77
71
  - bin/puppetmaster.rb
72
+ - bin/router
78
73
  - docs/design.graphml
79
74
  - docs/design.png
80
75
  - example/Procfile
81
76
  - example/client.rb
82
77
  - example/common.rb
83
- - example/device.yml
78
+ - example/router.yml
84
79
  - example/worker.rb
85
80
  - example2/Procfile
86
81
  - example2/README.md
87
- - example2/device.yml
88
82
  - example2/node.rb
83
+ - example2/router.yml
89
84
  - foreign_actor.gemspec
90
85
  - lib/foreign_actor.rb
91
86
  - lib/foreign_actor/client.rb
@@ -98,32 +93,25 @@ files:
98
93
  - specs/unit/serializer_spec.rb
99
94
  homepage: ''
100
95
  licenses: []
96
+ metadata: {}
101
97
  post_install_message:
102
98
  rdoc_options: []
103
99
  require_paths:
104
100
  - lib
105
101
  required_ruby_version: !ruby/object:Gem::Requirement
106
- none: false
107
102
  requirements:
108
- - - ! '>='
103
+ - - '>='
109
104
  - !ruby/object:Gem::Version
110
105
  version: '0'
111
- segments:
112
- - 0
113
- hash: 2556761358232140633
114
106
  required_rubygems_version: !ruby/object:Gem::Requirement
115
- none: false
116
107
  requirements:
117
- - - ! '>='
108
+ - - '>='
118
109
  - !ruby/object:Gem::Version
119
110
  version: '0'
120
- segments:
121
- - 0
122
- hash: 2556761358232140633
123
111
  requirements: []
124
112
  rubyforge_project:
125
- rubygems_version: 1.8.24
113
+ rubygems_version: 2.0.3
126
114
  signing_key:
127
- specification_version: 3
115
+ specification_version: 4
128
116
  summary: Distributed Actors
129
117
  test_files: []