zactor 0.0.7 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -9,7 +9,7 @@ group :development do
9
9
  gem "rr"
10
10
  gem "guard-rspec"
11
11
  gem "growl"
12
- gem "ruby-debug19"
12
+ gem "ruby-debug19", :platform => :mri_19
13
13
  gem "em-spec", :git => "https://github.com/mloughran/em-spec.git", :branch => 'rspec2'
14
14
  end
15
15
 
@@ -8,7 +8,7 @@ GIT
8
8
  PATH
9
9
  remote: .
10
10
  specs:
11
- zactor (0.0.7)
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.0)
27
- bson_ext (1.3.0)
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.7)
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
- zactor.actor =>
10
- {"identity"=>"actor.2154247120-0.0.0.0:8000", "host"=>"0.0.0.0:8000"}
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
- * Непосрдественной передачей. При инициализации или в любом другом месте, это исключительно внутренняя логика приложения. Идентификатор объекта можно получить вызвав zactor.actor
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
- В коллбэк определенный в event передается объект получившый сообщение, объект сообщения ({Zactor::Message}) и далее переданные в запросе аргументы (если они есть). У {Zactor::Message} есть два основных метода: sender, возвращающий идентификатор отправителя и reply, который посылает ответ на запрос.
115
+ В коллбэк, определенный в event, передается объект, получивший сообщение, объект сообщения ({Zactor::Message}) и далее переданные в запросе аргументы (если они есть). У {Zactor::Message} есть два основных метода: sender, возвращающий идентификатор отправителя и reply, который посылает ответ на запрос.
105
116
 
106
117
  Важный момент, identity должно задаваться ДО zactor.init и после этого не может меняться.
107
118
 
@@ -12,14 +12,21 @@ class A
12
12
  include Zactor
13
13
 
14
14
  def initialize
15
+ @counter = 0
15
16
  zactor.init
16
- ping Zactor.get_actor("b")
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
- puts res
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
- Zactor.start 8000
53
+
54
+ Zactor.start ARGV[0]
47
55
 
48
56
  a = A.new
49
57
  b = B.new
58
+ a.start
50
59
  end
@@ -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
- def broker
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] = true
40
+ @zactors[zactor.identity] = zactor
52
41
  end
53
42
 
54
43
  def deregister(zactor)
55
- @zactors.delete zactor
44
+ @zactors ||= {}
45
+ @zactors.delete zactor.identity
56
46
  end
57
47
 
58
48
  def finish
59
- @zactors.keys.each(&:finish)
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 @identity || self.class.identity_val || "actor.#{owner.object_id}-#{Zactor.host}"
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 make_pub(endpoint)
162
- Zactor::ActorPub.new self, endpoint
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 "#{clb ? clb.object_id : ''}"
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
- Zactor.logger.debug "Zactor: send reply"
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 = @pubs[actor['host']] ||= make_pub("tcp://#{actor['host']}")
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(5) do
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(5) do
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[callback_id])
239
- if timeout = @timeouts[callback_id]
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
- event.call owner, mes, *args
251
- else
252
- raise "Undefined event #{event_name}"
253
- end
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
@@ -3,9 +3,8 @@ module Zactor
3
3
  include ZMQMEssages
4
4
 
5
5
  attr_accessor :actor
6
- def initialize(actor, endpoint)
7
- Zactor.logger.debug "ZactorPub (#{actor.actor}): starting"
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
@@ -9,26 +9,7 @@ module Zactor
9
9
 
10
10
  def on_readable(socket, messages)
11
11
  Zactor.logger.debug "Broker: messages"
12
- @broker.pub.request messages
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
@@ -1,3 +1,3 @@
1
1
  module Zactor
2
- VERSION = "0.0.7"
3
- end
2
+ VERSION = "0.0.8"
3
+ end
@@ -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
- before do
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(local_pub).send_messages do |mes|
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 Zactor.get_actor('b')
65
+ actor.send_to remote_actor
77
66
  end
78
67
 
79
68
  it "должен отправить в удаленный pub для удаленного объекта, перед этим создав его" do
80
- remote_pub = Object.new
81
- mock(actor).make_pub("tcp://192.168.1.1:3000") { remote_pub }
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 Zactor.get_actor('b', :host => '192.168.1.1:3000')
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
- stub(local_pub).send_messages do |mes|
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 Zactor.get_actor('b'), :show, 'foo', :bar
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
- stub(local_pub).send_messages do |mes|
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 Zactor.get_actor('b'), 5, 'foo', :bar
108
+ actor.send_reply remote_actor, 5, 'foo', :bar
119
109
  end
120
110
  end
121
111
 
@@ -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
- after do
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
- em do
56
- Zactor.start 8000, :debug => true
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 { done }
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
- em do
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 { done }
79
+ mock.proxy(a).reply { em_done }
80
+ a.ping
70
81
  end
71
82
  end
72
83
 
73
84
  it "Если задан таймаут, то он должен срабатывать" do
74
- em(7) do
75
- Zactor.start 8000, :debug => true
85
+ em_start(7) do
76
86
  a = Exchange::A.new.ping.timeout(5) do
77
- done
87
+ em_done
78
88
  end
79
89
  end
80
90
  end
@@ -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 = %q{2011-03-24}
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
- prerelease: false
5
- segments:
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
- date: 2011-03-24 00:00:00 +03:00
18
- default_executable:
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: &id001 !ruby/object:Gem::Requirement
16
+ requirement: &2161481500 !ruby/object:Gem::Requirement
23
17
  none: false
24
- requirements:
25
- - - ">"
26
- - !ruby/object:Gem::Version
27
- segments:
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: *id001
34
- - !ruby/object:Gem::Dependency
24
+ version_requirements: *2161481500
25
+ - !ruby/object:Gem::Dependency
35
26
  name: ruby-interface
36
- requirement: &id002 !ruby/object:Gem::Requirement
27
+ requirement: &2161480500 !ruby/object:Gem::Requirement
37
28
  none: false
38
- requirements:
39
- - - ">"
40
- - !ruby/object:Gem::Version
41
- segments:
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: *id002
47
- - !ruby/object:Gem::Dependency
35
+ version_requirements: *2161480500
36
+ - !ruby/object:Gem::Dependency
48
37
  name: ffi-rzmq
49
- requirement: &id003 !ruby/object:Gem::Requirement
38
+ requirement: &2161479420 !ruby/object:Gem::Requirement
50
39
  none: false
51
- requirements:
52
- - - ">"
53
- - !ruby/object:Gem::Version
54
- segments:
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: *id003
61
- - !ruby/object:Gem::Dependency
46
+ version_requirements: *2161479420
47
+ - !ruby/object:Gem::Dependency
62
48
  name: em-zeromq
63
- requirement: &id004 !ruby/object:Gem::Requirement
49
+ requirement: &2161478460 !ruby/object:Gem::Requirement
64
50
  none: false
65
- requirements:
66
- - - ">"
67
- - !ruby/object:Gem::Version
68
- segments:
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: *id004
75
- - !ruby/object:Gem::Dependency
57
+ version_requirements: *2161478460
58
+ - !ruby/object:Gem::Dependency
76
59
  name: bson
77
- requirement: &id005 !ruby/object:Gem::Requirement
60
+ requirement: &2161477700 !ruby/object:Gem::Requirement
78
61
  none: false
79
- requirements:
80
- - - ">"
81
- - !ruby/object:Gem::Version
82
- segments:
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: *id005
89
- - !ruby/object:Gem::Dependency
68
+ version_requirements: *2161477700
69
+ - !ruby/object:Gem::Dependency
90
70
  name: bson_ext
91
- requirement: &id006 !ruby/object:Gem::Requirement
71
+ requirement: &2161477000 !ruby/object:Gem::Requirement
92
72
  none: false
93
- requirements:
94
- - - ">"
95
- - !ruby/object:Gem::Version
96
- segments:
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: *id006
103
- - !ruby/object:Gem::Dependency
79
+ version_requirements: *2161477000
80
+ - !ruby/object:Gem::Dependency
104
81
  name: activesupport
105
- requirement: &id007 !ruby/object:Gem::Requirement
82
+ requirement: &2161476360 !ruby/object:Gem::Requirement
106
83
  none: false
107
- requirements:
108
- - - ">"
109
- - !ruby/object:Gem::Version
110
- segments:
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: *id007
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
- hash: 1512131416648626830
170
- segments:
145
+ requirements:
146
+ - - ! '>='
147
+ - !ruby/object:Gem::Version
148
+ version: '0'
149
+ segments:
171
150
  - 0
172
- version: "0"
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
- segments:
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.3.7
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