zactor 0.0.7 → 0.0.8
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.
- data/Gemfile +1 -1
- data/Gemfile.lock +8 -5
- data/README.md +33 -22
- data/examples/ping/inproc.rb +14 -5
- data/lib/zactor.rb +59 -46
- data/lib/zactor/actor_pub.rb +2 -3
- data/lib/zactor/broker.rb +32 -22
- data/lib/zactor/version.rb +2 -2
- data/spec/lib/actor_spec.rb +23 -33
- data/spec/lib/exchange_spec.rb +22 -12
- data/zactor.gemspec +2 -1
- metadata +83 -107
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -8,7 +8,7 @@ GIT
|
|
8
8
|
PATH
|
9
9
|
remote: .
|
10
10
|
specs:
|
11
|
-
zactor (0.0.
|
11
|
+
zactor (0.0.8)
|
12
12
|
activesupport (> 0.1)
|
13
13
|
bson (> 0.1)
|
14
14
|
bson_ext (> 0.1)
|
@@ -16,6 +16,7 @@ PATH
|
|
16
16
|
ffi (> 0.1)
|
17
17
|
ffi-rzmq (> 0.1)
|
18
18
|
ruby-interface (> 0)
|
19
|
+
uuid (> 0.1)
|
19
20
|
|
20
21
|
GEM
|
21
22
|
remote: http://rubygems.org/
|
@@ -23,8 +24,8 @@ GEM
|
|
23
24
|
activesupport (3.0.7)
|
24
25
|
archive-tar-minitar (0.5.2)
|
25
26
|
bluecloth (2.1.0)
|
26
|
-
bson (1.3.
|
27
|
-
bson_ext (1.3.
|
27
|
+
bson (1.3.1)
|
28
|
+
bson_ext (1.3.1)
|
28
29
|
columnize (0.3.2)
|
29
30
|
configuration (1.2.0)
|
30
31
|
diff-lcs (1.1.2)
|
@@ -32,8 +33,7 @@ GEM
|
|
32
33
|
eventmachine (>= 1.0.0.beta.3)
|
33
34
|
ffi-rzmq (>= 0.7.2)
|
34
35
|
eventmachine (1.0.0.beta.3)
|
35
|
-
ffi (1.0.
|
36
|
-
rake (>= 0.8.7)
|
36
|
+
ffi (1.0.9)
|
37
37
|
ffi-rzmq (0.8.0)
|
38
38
|
growl (1.0.3)
|
39
39
|
guard (0.3.0)
|
@@ -47,6 +47,7 @@ GEM
|
|
47
47
|
rake (>= 0.8.1)
|
48
48
|
linecache19 (0.5.11)
|
49
49
|
ruby_core_source (>= 0.1.4)
|
50
|
+
macaddr (1.0.0)
|
50
51
|
open_gem (1.4.2)
|
51
52
|
launchy (~> 0.3.5)
|
52
53
|
rake (0.8.7)
|
@@ -74,6 +75,8 @@ GEM
|
|
74
75
|
ruby_core_source (0.1.4)
|
75
76
|
archive-tar-minitar (>= 0.5.2)
|
76
77
|
thor (0.14.6)
|
78
|
+
uuid (2.3.2)
|
79
|
+
macaddr (~> 1.0)
|
77
80
|
yard (0.6.5)
|
78
81
|
|
79
82
|
PLATFORMS
|
data/README.md
CHANGED
@@ -6,43 +6,52 @@ Zactor использует zmq как бекенд для сообщений, e
|
|
6
6
|
|
7
7
|
Каждый zactor-объект имеет свой identity, который генерируется автоматически, либо задается вручную и постоянен. Совокупность identity, host и port на которых был рожден этот объект, это достаточная информация для того что бы отправить этому объекту сообщение из другого объекта. Выглядит примерно так:
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
```ruby
|
10
|
+
zactor.actor => {"identity"=>"actor.2154247120-0.0.0.0:8000", "host"=>"0.0.0.0:8000"}
|
11
|
+
```
|
12
|
+
|
13
|
+
Использование
|
13
14
|
============
|
14
15
|
|
15
16
|
Для начала нужно стартануть Zactor.
|
16
|
-
|
17
|
+
|
18
|
+
```ruby
|
17
19
|
Zactor.start 8000
|
18
|
-
|
20
|
+
```
|
21
|
+
|
19
22
|
Процесс забиндится на 0.0.0.0:8000, через эту точку будет происходить общение между zactor-процессами. Стартоваться должен в запущенном EM-контексте.
|
20
23
|
|
21
24
|
В каждый zactor-активный класс нужно делать include Zactor, после чего у класса и его экземпляров для доступа к функциями Zactor появится метод zactor. После создания объекта нужно выполнить zactor.init
|
22
25
|
|
26
|
+
```ruby
|
23
27
|
class A
|
24
28
|
include Zactor
|
25
|
-
|
29
|
+
|
26
30
|
def initialize
|
27
31
|
zactor.init
|
28
32
|
end
|
29
33
|
end
|
30
|
-
|
34
|
+
```
|
35
|
+
|
31
36
|
Для отправки сообщений другому объекту нам нужно знать его идентификатор. Идентификатор можно получить тремя способами:
|
32
37
|
|
33
|
-
*
|
38
|
+
* Непосредственной передачей. При инициализации или в любом другом месте, это исключительно внутренняя логика приложения. Идентификатор объекта можно получить вызвав zactor.actor
|
34
39
|
* При получении сообщения. В сообщении всегда содержится информация об отправителе
|
35
40
|
* Если объект имеет заранее известный identity, то мы можем получить его полный идентификатор вызвав Zactor.get_actor с identity и хостом, на котором он запущен
|
36
|
-
|
41
|
+
|
42
|
+
```ruby
|
37
43
|
actor = Zactor.get_actor "broker", :host => "0.0.0.0:8001"
|
38
|
-
|
39
|
-
|
40
|
-
|
44
|
+
```
|
45
|
+
|
46
|
+
Получив идентификатор, можно отправлять ему сообщения
|
47
|
+
|
48
|
+
```ruby
|
41
49
|
zactor.send_request actor, :show_me, :boobs
|
50
|
+
```
|
42
51
|
|
43
|
-
|
44
|
-
|
45
|
-
|
52
|
+
Каждый класс может определять, какие именно события он может получать и что с ними делать
|
53
|
+
|
54
|
+
```ruby
|
46
55
|
include Zactor
|
47
56
|
|
48
57
|
zactor do
|
@@ -55,9 +64,11 @@ Zactor использует zmq как бекенд для сообщений, e
|
|
55
64
|
end
|
56
65
|
end
|
57
66
|
end
|
58
|
-
|
67
|
+
```
|
68
|
+
|
59
69
|
Рассмотрим пример банального ping-pong
|
60
70
|
|
71
|
+
```ruby
|
61
72
|
class A
|
62
73
|
include Zactor
|
63
74
|
|
@@ -65,7 +76,7 @@ Zactor использует zmq как бекенд для сообщений, e
|
|
65
76
|
zactor.init
|
66
77
|
ping Zactor.get_actor("b")
|
67
78
|
end
|
68
|
-
|
79
|
+
|
69
80
|
def ping(actor)
|
70
81
|
puts "Ping!"
|
71
82
|
zactor.send_request actor, :ping do |res|
|
@@ -74,10 +85,9 @@ Zactor использует zmq как бекенд для сообщений, e
|
|
74
85
|
end
|
75
86
|
end
|
76
87
|
|
77
|
-
|
78
88
|
class B
|
79
89
|
include Zactor
|
80
|
-
|
90
|
+
|
81
91
|
zactor do
|
82
92
|
identity "b"
|
83
93
|
|
@@ -98,10 +108,11 @@ Zactor использует zmq как бекенд для сообщений, e
|
|
98
108
|
a = A.new
|
99
109
|
b = B.new
|
100
110
|
end
|
101
|
-
|
111
|
+
```
|
112
|
+
|
102
113
|
A посылает сообщение :ping для B, а B отвечает "Pong!"
|
103
114
|
|
104
|
-
В
|
115
|
+
В коллбэк, определенный в event, передается объект, получивший сообщение, объект сообщения ({Zactor::Message}) и далее переданные в запросе аргументы (если они есть). У {Zactor::Message} есть два основных метода: sender, возвращающий идентификатор отправителя и reply, который посылает ответ на запрос.
|
105
116
|
|
106
117
|
Важный момент, identity должно задаваться ДО zactor.init и после этого не может меняться.
|
107
118
|
|
data/examples/ping/inproc.rb
CHANGED
@@ -12,14 +12,21 @@ class A
|
|
12
12
|
include Zactor
|
13
13
|
|
14
14
|
def initialize
|
15
|
+
@counter = 0
|
15
16
|
zactor.init
|
16
|
-
|
17
|
+
end
|
18
|
+
|
19
|
+
def start
|
20
|
+
ping Zactor.get_actor("b", :host => "0.0.0.0:#{ARGV[1]}")
|
17
21
|
end
|
18
22
|
|
19
|
-
def ping(actor)
|
20
|
-
puts "Ping!"
|
23
|
+
def ping(actor)
|
21
24
|
zactor.send_request actor, :ping do |res|
|
22
|
-
|
25
|
+
@counter += 1
|
26
|
+
if @counter % 1000 == 0
|
27
|
+
puts @counter
|
28
|
+
end
|
29
|
+
EM.next_tick { ping(actor) }
|
23
30
|
end
|
24
31
|
end
|
25
32
|
end
|
@@ -43,8 +50,10 @@ class B
|
|
43
50
|
end
|
44
51
|
|
45
52
|
EM.run do
|
46
|
-
|
53
|
+
|
54
|
+
Zactor.start ARGV[0]
|
47
55
|
|
48
56
|
a = A.new
|
49
57
|
b = B.new
|
58
|
+
a.start
|
50
59
|
end
|
data/lib/zactor.rb
CHANGED
@@ -4,12 +4,11 @@ require 'active_support/all'
|
|
4
4
|
require 'ffi-rzmq'
|
5
5
|
require 'em-zeromq'
|
6
6
|
require 'bson'
|
7
|
-
|
7
|
+
require 'uuid'
|
8
8
|
module Zactor
|
9
9
|
extend ActiveSupport::Autoload
|
10
|
-
|
10
|
+
LinkTimeout = LinkInterval = 20
|
11
11
|
autoload :Broker
|
12
|
-
autoload :ActorSub
|
13
12
|
autoload :ActorPub
|
14
13
|
autoload :Message
|
15
14
|
require 'zactor/log_subscriber'
|
@@ -17,19 +16,8 @@ module Zactor
|
|
17
16
|
mattr_accessor :stub
|
18
17
|
mattr_accessor :zmq, :logger
|
19
18
|
|
20
|
-
class << self
|
21
|
-
|
22
|
-
@broker
|
23
|
-
end
|
24
|
-
|
25
|
-
def broker_port
|
26
|
-
@broker_port
|
27
|
-
end
|
28
|
-
|
29
|
-
def host
|
30
|
-
@host
|
31
|
-
end
|
32
|
-
|
19
|
+
class << self
|
20
|
+
attr_accessor :broker, :broker_port, :host, :zactors
|
33
21
|
def start(broker_port, params = {})
|
34
22
|
self.zmq ||= EM::ZeroMQ::Context.new(1)
|
35
23
|
self.logger ||= Logger.new(STDOUT).tap { |o| o.level = params[:debug] ? Logger::DEBUG : Logger::INFO }
|
@@ -39,6 +27,7 @@ module Zactor
|
|
39
27
|
|
40
28
|
logger.info "Starting Zactor"
|
41
29
|
@broker = Broker.new :balancer => params[:balancer]
|
30
|
+
@pubs = {}
|
42
31
|
end
|
43
32
|
|
44
33
|
def get_actor(pid, options = {})
|
@@ -48,18 +37,24 @@ module Zactor
|
|
48
37
|
|
49
38
|
def register(zactor)
|
50
39
|
@zactors ||= {}
|
51
|
-
@zactors[zactor] =
|
40
|
+
@zactors[zactor.identity] = zactor
|
52
41
|
end
|
53
42
|
|
54
43
|
def deregister(zactor)
|
55
|
-
@zactors
|
44
|
+
@zactors ||= {}
|
45
|
+
@zactors.delete zactor.identity
|
56
46
|
end
|
57
47
|
|
58
48
|
def finish
|
59
|
-
@zactors.
|
49
|
+
@zactors.values.each(&:finish)
|
50
|
+
@pubs.values.each(&:close)
|
60
51
|
@broker.finish
|
61
52
|
end
|
62
53
|
|
54
|
+
def pub(actor)
|
55
|
+
@pubs[actor['host']] ||= Zactor::ActorPub.new("tcp://#{actor['host']}")
|
56
|
+
end
|
57
|
+
|
63
58
|
def clear
|
64
59
|
@zactors = {}
|
65
60
|
end
|
@@ -131,17 +126,13 @@ module Zactor
|
|
131
126
|
end
|
132
127
|
end
|
133
128
|
attr_accessor :actor, :identity
|
134
|
-
attr_accessor :pubs
|
135
129
|
|
136
130
|
# Инициализация, подписывается на сообщения для себя, создает сокет для отправки локальных сообщений
|
137
131
|
def init
|
138
|
-
@actor = Zactor.get_actor
|
132
|
+
@actor = Zactor.get_actor identity
|
139
133
|
Zactor.register self
|
140
134
|
return if Zactor.stub
|
141
|
-
@sub = make_sub
|
142
135
|
@callbacks, @timeouts = {}, {}
|
143
|
-
@pubs = {}
|
144
|
-
@pubs["0.0.0.0:#{Zactor.broker_port}"] = make_pub "inproc://zactor_broker_sub"
|
145
136
|
end
|
146
137
|
|
147
138
|
# Закрываем все соедниения и чистим сисьему. Обязательно нужно делать, когда объект перестает существовать
|
@@ -154,40 +145,62 @@ module Zactor
|
|
154
145
|
end
|
155
146
|
end
|
156
147
|
@finished = true
|
157
|
-
@sub.close
|
158
|
-
@pubs.values.each(&:close)
|
159
148
|
end
|
160
149
|
|
161
|
-
def
|
162
|
-
|
163
|
-
end
|
164
|
-
|
165
|
-
def make_sub
|
166
|
-
Zactor::ActorSub.new self
|
150
|
+
def identity
|
151
|
+
@identity ||= self.class.identity_val || "actor.#{UUID.generate}-#{Zactor.host}"
|
167
152
|
end
|
168
153
|
|
169
154
|
def send_request(actor, event, *args, &clb)
|
170
155
|
return if @finished || Zactor.stub
|
171
156
|
@callbacks[clb.object_id.to_s] = clb if clb
|
157
|
+
@last_callback = clb ? clb.object_id.to_s : ''
|
158
|
+
if actor['host'] == @actor['host']
|
159
|
+
internal_request actor, event, @last_callback, *args
|
160
|
+
else
|
161
|
+
extertanl_request actor, event, @last_callback, *args
|
162
|
+
end
|
163
|
+
self
|
164
|
+
end
|
165
|
+
|
166
|
+
def internal_request(actor, event, clb_id, *args)
|
167
|
+
receiver = Zactor.zactors[actor['identity']]
|
168
|
+
return unless receiver
|
169
|
+
receiver.receive_request @actor, event, clb_id, *args
|
170
|
+
end
|
171
|
+
|
172
|
+
def extertanl_request(actor, event, clb_id, *args)
|
172
173
|
send_to actor, messages { |m|
|
173
174
|
m.str 'request'
|
174
|
-
m.str
|
175
|
+
m.str clb_id
|
175
176
|
m.str event
|
176
177
|
m.str BSON.serialize({ 'args' => args })
|
177
178
|
}
|
178
|
-
@last_callback = clb.object_id.to_s
|
179
|
-
self
|
180
179
|
end
|
181
180
|
|
182
181
|
def timeout(secs, &clb)
|
183
182
|
raise "Only for requests" unless @last_callback
|
183
|
+
return unless @callbacks[@last_callback] # в случае если коллбэк уже был выполнен синхронно
|
184
184
|
last_clb = @last_callback
|
185
185
|
@timeouts[last_clb] = EM.add_timer(secs) { @timeouts.delete(last_clb); clb.call }
|
186
186
|
end
|
187
187
|
|
188
188
|
def send_reply(actor, callback_id, *args)
|
189
189
|
return if @finished || Zactor.stub
|
190
|
-
|
190
|
+
if actor['host'] == @actor['host']
|
191
|
+
internal_reply actor, callback_id, *args
|
192
|
+
else
|
193
|
+
external_reply actor, callback_id, *args
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
def internal_reply(actor, callback_id, *args)
|
198
|
+
receiver = Zactor.zactors[actor['identity']]
|
199
|
+
return unless receiver
|
200
|
+
receiver.receive_reply callback_id, *args
|
201
|
+
end
|
202
|
+
|
203
|
+
def external_reply(actor, callback_id, *args)
|
191
204
|
send_to actor, messages { |m|
|
192
205
|
m.str 'reply'
|
193
206
|
m.str callback_id
|
@@ -196,7 +209,7 @@ module Zactor
|
|
196
209
|
end
|
197
210
|
|
198
211
|
def send_to(actor, mes = [])
|
199
|
-
pub =
|
212
|
+
pub = Zactor.pub actor
|
200
213
|
pub.send_messages(messages { |m|
|
201
214
|
m.str actor['identity']
|
202
215
|
m.str bson_actor
|
@@ -216,11 +229,11 @@ module Zactor
|
|
216
229
|
end
|
217
230
|
|
218
231
|
def link_ping(link_timer, actor, &clb)
|
219
|
-
link_timer[:timer] = EM.add_timer(
|
232
|
+
link_timer[:timer] = EM.add_timer(LinkInterval) do
|
220
233
|
unless @finished
|
221
234
|
send_request(actor, :link_ping) do
|
222
235
|
link_ping link_timer, actor, &clb
|
223
|
-
end.timeout(
|
236
|
+
end.timeout(LinkTimeout) do
|
224
237
|
clb.call
|
225
238
|
end
|
226
239
|
end
|
@@ -235,8 +248,8 @@ module Zactor
|
|
235
248
|
|
236
249
|
def receive_reply(callback_id, *args)
|
237
250
|
Zactor.logger.debug "Zactor: receive reply"
|
238
|
-
if (callback = @callbacks
|
239
|
-
if timeout = @timeouts
|
251
|
+
if (callback = @callbacks.delete(callback_id))
|
252
|
+
if timeout = @timeouts.delete(callback_id)
|
240
253
|
EM.cancel_timer timeout
|
241
254
|
end
|
242
255
|
callback.call(*args)
|
@@ -247,10 +260,10 @@ module Zactor
|
|
247
260
|
Zactor.logger.debug "Zactor: receive request"
|
248
261
|
mes = Message.new self, :sender => sender, :callback_id => callback_id, :args => args
|
249
262
|
if (event = self.class.events[event_name.to_sym])
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
263
|
+
event.call(owner, mes, *args)
|
264
|
+
else
|
265
|
+
raise "Undefined event #{event_name}"
|
266
|
+
end
|
254
267
|
end
|
255
268
|
|
256
269
|
def bson_actor
|
@@ -264,4 +277,4 @@ module Zactor
|
|
264
277
|
|
265
278
|
end
|
266
279
|
|
267
|
-
end
|
280
|
+
end
|
data/lib/zactor/actor_pub.rb
CHANGED
@@ -3,9 +3,8 @@ module Zactor
|
|
3
3
|
include ZMQMEssages
|
4
4
|
|
5
5
|
attr_accessor :actor
|
6
|
-
def initialize(
|
7
|
-
Zactor.logger.debug "ZactorPub (#{
|
8
|
-
@actor = actor
|
6
|
+
def initialize(endpoint)
|
7
|
+
Zactor.logger.debug "ZactorPub (#{endpoint}): starting"
|
9
8
|
@connection = Zactor.zmq.connect ZMQ::PUB, endpoint, self
|
10
9
|
@socket = @connection.socket
|
11
10
|
end
|
data/lib/zactor/broker.rb
CHANGED
@@ -9,26 +9,7 @@ module Zactor
|
|
9
9
|
|
10
10
|
def on_readable(socket, messages)
|
11
11
|
Zactor.logger.debug "Broker: messages"
|
12
|
-
@broker.
|
13
|
-
end
|
14
|
-
|
15
|
-
def close
|
16
|
-
@connection.unbind
|
17
|
-
rescue
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
class BrokerPub
|
22
|
-
include ZMQMEssages
|
23
|
-
def initialize(broker)
|
24
|
-
@broker = broker
|
25
|
-
@connection = Zactor.zmq.bind ZMQ::PUB, "inproc://zactor_broker_pub", self
|
26
|
-
@socket = @connection.socket
|
27
|
-
end
|
28
|
-
|
29
|
-
def request(messages)
|
30
|
-
Zactor.logger.debug { "Broker: request #{messages.map(&:copy_out_string).inspect}" }
|
31
|
-
send_messages messages
|
12
|
+
@broker.dispatch_request messages
|
32
13
|
end
|
33
14
|
|
34
15
|
def close
|
@@ -57,14 +38,43 @@ module Zactor
|
|
57
38
|
attr_accessor :sub, :pub
|
58
39
|
def initialize(params = {})
|
59
40
|
Zactor.logger.info "Broker: starting"
|
60
|
-
@pub = BrokerPub.new self
|
61
41
|
@subs = []
|
62
42
|
@subs << BrokerSub.new(self)
|
63
43
|
@subs << BrokerPull.new(self, :host => params[:balancer]) if params[:balancer]
|
64
44
|
end
|
65
45
|
|
46
|
+
def dispatch_request(messages)
|
47
|
+
to = messages.shift.copy_out_string
|
48
|
+
actor = Zactor.zactors[to]
|
49
|
+
return unless actor
|
50
|
+
Zactor.logger.debug "ZactorSub for #{actor.actor}: Messages!"
|
51
|
+
sender = messages.shift
|
52
|
+
case messages.shift.copy_out_string
|
53
|
+
when "reply"
|
54
|
+
reply actor, messages
|
55
|
+
when "request"
|
56
|
+
request actor, sender, messages
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def request(actor, sender_mes, messages)
|
61
|
+
Zactor.logger.debug "ZactorSub for #{actor.actor}: request!"
|
62
|
+
sender = BSON.deserialize(sender_mes.copy_out_string)
|
63
|
+
callback_id = messages[0].copy_out_string
|
64
|
+
event = messages[1].copy_out_string
|
65
|
+
args = BSON.deserialize(messages[2].copy_out_string)['args']
|
66
|
+
actor.receive_request sender, event, callback_id, *args
|
67
|
+
end
|
68
|
+
|
69
|
+
def reply(actor, messages)
|
70
|
+
Zactor.logger.debug "ZactorSub for #{actor.actor}: reply!"
|
71
|
+
callback_id = messages[0].copy_out_string
|
72
|
+
if callback_id != ''
|
73
|
+
actor.receive_reply callback_id, *BSON.deserialize(messages[1].copy_out_string)['args']
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
66
77
|
def finish
|
67
|
-
@pub.close
|
68
78
|
@subs.each(&:close)
|
69
79
|
end
|
70
80
|
end
|
data/lib/zactor/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
1
|
module Zactor
|
2
|
-
VERSION = "0.0.
|
3
|
-
end
|
2
|
+
VERSION = "0.0.8"
|
3
|
+
end
|
data/spec/lib/actor_spec.rb
CHANGED
@@ -14,32 +14,13 @@ describe "Zactor actor" do
|
|
14
14
|
let(:actor) { A.new.zactor }
|
15
15
|
let(:sub) { Object.new }
|
16
16
|
let(:local_pub) { Object.new }
|
17
|
-
|
18
|
-
stub(actor).make_sub { sub }
|
19
|
-
stub(actor).make_pub { local_pub }
|
20
|
-
end
|
17
|
+
|
21
18
|
it "должен зарегистрировать себя" do
|
22
19
|
mock(Zactor).register actor
|
23
20
|
actor.init
|
24
21
|
end
|
25
22
|
|
26
|
-
it "должен создать sub сокет" do
|
27
|
-
mock(actor).make_sub { sub }
|
28
|
-
actor.init
|
29
|
-
actor.instance_eval { @sub }.should eq(sub)
|
30
|
-
end
|
31
|
-
|
32
|
-
it "должен создать pub сокет для локальных вызовов" do
|
33
|
-
mock(actor).make_pub("inproc://zactor_broker_sub") { local_pub }
|
34
|
-
actor.init
|
35
|
-
actor.instance_eval { @pubs['0.0.0.0:8000'] }.should eq(local_pub)
|
36
|
-
end
|
37
|
-
|
38
23
|
describe "identity" do
|
39
|
-
it "по-умолчанию" do
|
40
|
-
actor.init
|
41
|
-
actor.actor.should eq({ 'identity' => "actor.#{actor.owner.object_id}-0.0.0.0:8000", 'host' => '0.0.0.0:8000' })
|
42
|
-
end
|
43
24
|
|
44
25
|
it "с глобальным указанием" do
|
45
26
|
A.zactor.identity "a"
|
@@ -61,61 +42,70 @@ describe "Zactor actor" do
|
|
61
42
|
got.map(&:copy_out_string).should eq(expected.map(&:copy_out_string))
|
62
43
|
end
|
63
44
|
|
45
|
+
def remote_pub(actor)
|
46
|
+
Zactor.pub(actor)
|
47
|
+
end
|
48
|
+
|
64
49
|
before do
|
65
50
|
actor.init
|
51
|
+
Zactor.instance_eval { @pubs['192.168.1.1:3000'] = Object.new }
|
66
52
|
end
|
53
|
+
|
54
|
+
|
67
55
|
describe "send_to" do
|
68
56
|
it "должен отправить в локальный pub для локального объекта" do
|
57
|
+
remote_actor = Zactor.get_actor('b', :host => '192.168.1.1:3000')
|
69
58
|
mes = messages { |m| }
|
70
|
-
stub(
|
59
|
+
stub(remote_pub(remote_actor)).send_messages do |mes|
|
71
60
|
assert_messages mes, messages { |m|
|
72
61
|
m.str('b')
|
73
62
|
m.str(actor.bson_actor)
|
74
63
|
}
|
75
64
|
end
|
76
|
-
actor.send_to
|
65
|
+
actor.send_to remote_actor
|
77
66
|
end
|
78
67
|
|
79
68
|
it "должен отправить в удаленный pub для удаленного объекта, перед этим создав его" do
|
80
|
-
|
81
|
-
|
82
|
-
stub(remote_pub).send_messages do |mes|
|
69
|
+
remote_actor = Zactor.get_actor('b', :host => '192.168.1.1:3000')
|
70
|
+
stub(remote_pub(remote_actor)).send_messages do |mes|
|
83
71
|
assert_messages mes, messages { |m| m.str('b'); m.str(actor.bson_actor) }
|
84
72
|
end
|
85
|
-
actor.send_to
|
73
|
+
actor.send_to remote_actor
|
86
74
|
end
|
87
75
|
end
|
88
76
|
|
89
77
|
describe "send_request" do
|
90
78
|
it "должен отправлять сообщение типа request" do
|
91
|
-
|
79
|
+
remote_actor = Zactor.get_actor('b', :host => '192.168.1.1:3000')
|
80
|
+
stub(remote_pub(remote_actor)).send_messages do |mes|
|
92
81
|
assert_messages mes, messages { |m|
|
93
82
|
m.str('b')
|
94
83
|
m.str(actor.bson_actor)
|
95
|
-
|
84
|
+
|
96
85
|
m.str 'request'
|
97
86
|
m.str ""
|
98
87
|
m.str "show"
|
99
88
|
m.str BSON.serialize({ 'args' => ['foo', :bar] })
|
100
89
|
}
|
101
90
|
end
|
102
|
-
actor.send_request
|
91
|
+
actor.send_request remote_actor, :show, 'foo', :bar
|
103
92
|
end
|
104
93
|
end
|
105
|
-
|
94
|
+
|
106
95
|
describe "send_reply" do
|
107
96
|
it "должен отправлять сообщение типа reply" do
|
108
|
-
|
97
|
+
remote_actor = Zactor.get_actor('b', :host => '192.168.1.1:3000')
|
98
|
+
stub(remote_pub(remote_actor)).send_messages do |mes|
|
109
99
|
assert_messages mes, messages { |m|
|
110
100
|
m.str('b')
|
111
101
|
m.str(actor.bson_actor)
|
112
|
-
|
102
|
+
|
113
103
|
m.str 'reply'
|
114
104
|
m.str 5
|
115
105
|
m.str BSON.serialize({ 'args' => ['foo', :bar] })
|
116
106
|
}
|
117
107
|
end
|
118
|
-
actor.send_reply
|
108
|
+
actor.send_reply remote_actor, 5, 'foo', :bar
|
119
109
|
end
|
120
110
|
end
|
121
111
|
|
data/spec/lib/exchange_spec.rb
CHANGED
@@ -15,6 +15,8 @@ describe "Zactor" do
|
|
15
15
|
|
16
16
|
def ping(actor = Zactor.get_actor("b"))
|
17
17
|
zactor.send_request actor, :ping do |res|
|
18
|
+
require 'ruby-debug'
|
19
|
+
debugger if $t
|
18
20
|
reply
|
19
21
|
end
|
20
22
|
end
|
@@ -46,35 +48,43 @@ describe "Zactor" do
|
|
46
48
|
end
|
47
49
|
end
|
48
50
|
|
49
|
-
|
51
|
+
def em_start(timeout = 5, &blk)
|
52
|
+
em(timeout) do
|
53
|
+
Zactor.start 8000, :debug => true
|
54
|
+
blk.call
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
def em_done
|
50
60
|
Zactor.clear
|
51
61
|
Zactor.finish
|
62
|
+
EM.add_timer(0.1) { done }
|
52
63
|
end
|
53
64
|
|
54
65
|
it "B должен получить сообщение" do
|
55
|
-
|
56
|
-
|
57
|
-
Exchange::A.new.ping
|
66
|
+
em_start do
|
67
|
+
a = Exchange::A.new
|
58
68
|
b = Exchange::B.new
|
59
|
-
mock.proxy(b).receive {
|
69
|
+
mock.proxy(b).receive { em_done }
|
70
|
+
a.ping
|
71
|
+
|
60
72
|
end
|
61
73
|
end
|
62
74
|
|
63
75
|
it "A должен получить ответ" do
|
64
|
-
|
65
|
-
Zactor.start 8000, :debug => true
|
76
|
+
em_start do
|
66
77
|
a = Exchange::A.new
|
67
|
-
a.ping
|
68
78
|
Exchange::B.new
|
69
|
-
mock.proxy(a).reply {
|
79
|
+
mock.proxy(a).reply { em_done }
|
80
|
+
a.ping
|
70
81
|
end
|
71
82
|
end
|
72
83
|
|
73
84
|
it "Если задан таймаут, то он должен срабатывать" do
|
74
|
-
|
75
|
-
Zactor.start 8000, :debug => true
|
85
|
+
em_start(7) do
|
76
86
|
a = Exchange::A.new.ping.timeout(5) do
|
77
|
-
|
87
|
+
em_done
|
78
88
|
end
|
79
89
|
end
|
80
90
|
end
|
data/zactor.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.summary = "Zactor"
|
9
9
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
10
10
|
s.authors = ["Andrew Rudenko"]
|
11
|
-
s.date = %
|
11
|
+
s.date = Time.now.strftime('%Y-%m-%d')
|
12
12
|
s.description = %q{Zactor}
|
13
13
|
s.email = %q{ceo@prepor.ru}
|
14
14
|
|
@@ -24,5 +24,6 @@ Gem::Specification.new do |s|
|
|
24
24
|
s.add_dependency('bson', ["> 0.1"])
|
25
25
|
s.add_dependency('bson_ext', ["> 0.1"])
|
26
26
|
s.add_dependency('activesupport', ["> 0.1"])
|
27
|
+
s.add_dependency('uuid', ["> 0.1"])
|
27
28
|
end
|
28
29
|
|
metadata
CHANGED
@@ -1,128 +1,110 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: zactor
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
- 0
|
7
|
-
- 0
|
8
|
-
- 7
|
9
|
-
version: 0.0.7
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.8
|
5
|
+
prerelease:
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- Andrew Rudenko
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
dependencies:
|
20
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2011-09-23 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
21
15
|
name: ffi
|
22
|
-
requirement: &
|
16
|
+
requirement: &2161481500 !ruby/object:Gem::Requirement
|
23
17
|
none: false
|
24
|
-
requirements:
|
25
|
-
- -
|
26
|
-
- !ruby/object:Gem::Version
|
27
|
-
|
28
|
-
- 0
|
29
|
-
- 1
|
30
|
-
version: "0.1"
|
18
|
+
requirements:
|
19
|
+
- - ! '>'
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0.1'
|
31
22
|
type: :runtime
|
32
23
|
prerelease: false
|
33
|
-
version_requirements: *
|
34
|
-
- !ruby/object:Gem::Dependency
|
24
|
+
version_requirements: *2161481500
|
25
|
+
- !ruby/object:Gem::Dependency
|
35
26
|
name: ruby-interface
|
36
|
-
requirement: &
|
27
|
+
requirement: &2161480500 !ruby/object:Gem::Requirement
|
37
28
|
none: false
|
38
|
-
requirements:
|
39
|
-
- -
|
40
|
-
- !ruby/object:Gem::Version
|
41
|
-
|
42
|
-
- 0
|
43
|
-
version: "0"
|
29
|
+
requirements:
|
30
|
+
- - ! '>'
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
44
33
|
type: :runtime
|
45
34
|
prerelease: false
|
46
|
-
version_requirements: *
|
47
|
-
- !ruby/object:Gem::Dependency
|
35
|
+
version_requirements: *2161480500
|
36
|
+
- !ruby/object:Gem::Dependency
|
48
37
|
name: ffi-rzmq
|
49
|
-
requirement: &
|
38
|
+
requirement: &2161479420 !ruby/object:Gem::Requirement
|
50
39
|
none: false
|
51
|
-
requirements:
|
52
|
-
- -
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
|
55
|
-
- 0
|
56
|
-
- 1
|
57
|
-
version: "0.1"
|
40
|
+
requirements:
|
41
|
+
- - ! '>'
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0.1'
|
58
44
|
type: :runtime
|
59
45
|
prerelease: false
|
60
|
-
version_requirements: *
|
61
|
-
- !ruby/object:Gem::Dependency
|
46
|
+
version_requirements: *2161479420
|
47
|
+
- !ruby/object:Gem::Dependency
|
62
48
|
name: em-zeromq
|
63
|
-
requirement: &
|
49
|
+
requirement: &2161478460 !ruby/object:Gem::Requirement
|
64
50
|
none: false
|
65
|
-
requirements:
|
66
|
-
- -
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
|
69
|
-
- 0
|
70
|
-
- 1
|
71
|
-
version: "0.1"
|
51
|
+
requirements:
|
52
|
+
- - ! '>'
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.1'
|
72
55
|
type: :runtime
|
73
56
|
prerelease: false
|
74
|
-
version_requirements: *
|
75
|
-
- !ruby/object:Gem::Dependency
|
57
|
+
version_requirements: *2161478460
|
58
|
+
- !ruby/object:Gem::Dependency
|
76
59
|
name: bson
|
77
|
-
requirement: &
|
60
|
+
requirement: &2161477700 !ruby/object:Gem::Requirement
|
78
61
|
none: false
|
79
|
-
requirements:
|
80
|
-
- -
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
|
83
|
-
- 0
|
84
|
-
- 1
|
85
|
-
version: "0.1"
|
62
|
+
requirements:
|
63
|
+
- - ! '>'
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0.1'
|
86
66
|
type: :runtime
|
87
67
|
prerelease: false
|
88
|
-
version_requirements: *
|
89
|
-
- !ruby/object:Gem::Dependency
|
68
|
+
version_requirements: *2161477700
|
69
|
+
- !ruby/object:Gem::Dependency
|
90
70
|
name: bson_ext
|
91
|
-
requirement: &
|
71
|
+
requirement: &2161477000 !ruby/object:Gem::Requirement
|
92
72
|
none: false
|
93
|
-
requirements:
|
94
|
-
- -
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
|
97
|
-
- 0
|
98
|
-
- 1
|
99
|
-
version: "0.1"
|
73
|
+
requirements:
|
74
|
+
- - ! '>'
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0.1'
|
100
77
|
type: :runtime
|
101
78
|
prerelease: false
|
102
|
-
version_requirements: *
|
103
|
-
- !ruby/object:Gem::Dependency
|
79
|
+
version_requirements: *2161477000
|
80
|
+
- !ruby/object:Gem::Dependency
|
104
81
|
name: activesupport
|
105
|
-
requirement: &
|
82
|
+
requirement: &2161476360 !ruby/object:Gem::Requirement
|
106
83
|
none: false
|
107
|
-
requirements:
|
108
|
-
- -
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
|
111
|
-
- 0
|
112
|
-
- 1
|
113
|
-
version: "0.1"
|
84
|
+
requirements:
|
85
|
+
- - ! '>'
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0.1'
|
114
88
|
type: :runtime
|
115
89
|
prerelease: false
|
116
|
-
version_requirements: *
|
90
|
+
version_requirements: *2161476360
|
91
|
+
- !ruby/object:Gem::Dependency
|
92
|
+
name: uuid
|
93
|
+
requirement: &2161475720 !ruby/object:Gem::Requirement
|
94
|
+
none: false
|
95
|
+
requirements:
|
96
|
+
- - ! '>'
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0.1'
|
99
|
+
type: :runtime
|
100
|
+
prerelease: false
|
101
|
+
version_requirements: *2161475720
|
117
102
|
description: Zactor
|
118
103
|
email: ceo@prepor.ru
|
119
104
|
executables: []
|
120
|
-
|
121
105
|
extensions: []
|
122
|
-
|
123
106
|
extra_rdoc_files: []
|
124
|
-
|
125
|
-
files:
|
107
|
+
files:
|
126
108
|
- .document
|
127
109
|
- .gitignore
|
128
110
|
- .rspec
|
@@ -152,40 +134,34 @@ files:
|
|
152
134
|
- spec/lib/zactor_spec.rb
|
153
135
|
- spec/spec_helper.rb
|
154
136
|
- zactor.gemspec
|
155
|
-
has_rdoc: true
|
156
137
|
homepage:
|
157
138
|
licenses: []
|
158
|
-
|
159
139
|
post_install_message:
|
160
140
|
rdoc_options: []
|
161
|
-
|
162
|
-
require_paths:
|
141
|
+
require_paths:
|
163
142
|
- lib
|
164
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
143
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
165
144
|
none: false
|
166
|
-
requirements:
|
167
|
-
- -
|
168
|
-
- !ruby/object:Gem::Version
|
169
|
-
|
170
|
-
segments:
|
145
|
+
requirements:
|
146
|
+
- - ! '>='
|
147
|
+
- !ruby/object:Gem::Version
|
148
|
+
version: '0'
|
149
|
+
segments:
|
171
150
|
- 0
|
172
|
-
|
173
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
151
|
+
hash: -3905546204389082799
|
152
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
174
153
|
none: false
|
175
|
-
requirements:
|
176
|
-
- -
|
177
|
-
- !ruby/object:Gem::Version
|
178
|
-
|
179
|
-
- 0
|
180
|
-
version: "0"
|
154
|
+
requirements:
|
155
|
+
- - ! '>='
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
181
158
|
requirements: []
|
182
|
-
|
183
159
|
rubyforge_project:
|
184
|
-
rubygems_version: 1.
|
160
|
+
rubygems_version: 1.8.5
|
185
161
|
signing_key:
|
186
162
|
specification_version: 3
|
187
163
|
summary: Zactor
|
188
|
-
test_files:
|
164
|
+
test_files:
|
189
165
|
- spec/lib/actor_spec.rb
|
190
166
|
- spec/lib/exchange_spec.rb
|
191
167
|
- spec/lib/link_spec.rb
|