em-zmq-tp10 0.1.7
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +237 -0
- data/Rakefile +9 -0
- data/em-zmq-tp10.gemspec +23 -0
- data/lib/em-zmq-tp10.rb +1 -0
- data/lib/em/protocols/zmq2.rb +25 -0
- data/lib/em/protocols/zmq2/connection.rb +37 -0
- data/lib/em/protocols/zmq2/dealer.rb +133 -0
- data/lib/em/protocols/zmq2/inproc.rb +147 -0
- data/lib/em/protocols/zmq2/pub_sub.rb +102 -0
- data/lib/em/protocols/zmq2/queue_per_peer.rb +57 -0
- data/lib/em/protocols/zmq2/rep.rb +64 -0
- data/lib/em/protocols/zmq2/req.rb +325 -0
- data/lib/em/protocols/zmq2/router.rb +69 -0
- data/lib/em/protocols/zmq2/socket.rb +236 -0
- data/lib/em/protocols/zmq2/socket_connection.rb +151 -0
- data/lib/em/protocols/zmq2/version.rb +7 -0
- data/lib/em/protocols/zmq_tp10.rb +2 -0
- data/tests/helper.rb +102 -0
- data/tests/run_all.rb +3 -0
- data/tests/test_dealer.rb +237 -0
- data/tests/test_inproc.rb +113 -0
- data/tests/test_pub_sub.rb +271 -0
- data/tests/test_reconnect.rb +64 -0
- data/tests/test_rep.rb +117 -0
- data/tests/test_req.rb +229 -0
- data/tests/test_router.rb +221 -0
- metadata +108 -0
data/tests/test_req.rb
ADDED
@@ -0,0 +1,229 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require File.expand_path('../helper.rb', __FILE__)
|
4
|
+
|
5
|
+
require 'em/protocols/zmq2/req'
|
6
|
+
|
7
|
+
describe 'Req' do
|
8
|
+
let(:connected) do
|
9
|
+
EM::DefaultDeferrable.new
|
10
|
+
end
|
11
|
+
|
12
|
+
describe EM::Protocols::Zmq2::PreReq do
|
13
|
+
class MyPreReq < EM::Protocols::Zmq2::PreReq
|
14
|
+
attr :incoming_queue
|
15
|
+
def initialize(opts={})
|
16
|
+
super
|
17
|
+
@connected = opts[:connected]
|
18
|
+
@incoming_queue = []
|
19
|
+
end
|
20
|
+
def peer_free(peer_identity, connection)
|
21
|
+
super
|
22
|
+
@connected.succeed
|
23
|
+
end
|
24
|
+
def receive_reply(message, data, request_id)
|
25
|
+
message.first.must_equal 'world'
|
26
|
+
message.last.must_equal data.to_s
|
27
|
+
@incoming_queue << ['hello', message.last]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
attr :req
|
32
|
+
before do
|
33
|
+
@req = MyPreReq.new(identity: 'REQ', connected: connected)
|
34
|
+
@req.connect(Native::ZBIND_ADDR)
|
35
|
+
end
|
36
|
+
|
37
|
+
let(:messages){
|
38
|
+
300.times.map{|i| ['hello', i.to_s]} << ['hello', 'xxx']
|
39
|
+
}
|
40
|
+
|
41
|
+
it 'should send requests' do
|
42
|
+
Native.with_socket('REP') do |zrep|
|
43
|
+
thrd = Thread.new do
|
44
|
+
messages.size.times do
|
45
|
+
ar = []
|
46
|
+
zrep.recv_strings ar
|
47
|
+
ar[0] = 'world'
|
48
|
+
zrep.send_strings ar
|
49
|
+
end
|
50
|
+
end
|
51
|
+
EM.run {
|
52
|
+
connected.callback {
|
53
|
+
dup = messages.dup
|
54
|
+
cb = lambda {
|
55
|
+
if dup.empty?
|
56
|
+
EM.add_timer(0.3){
|
57
|
+
EM.next_tick{ EM.stop }
|
58
|
+
}
|
59
|
+
else
|
60
|
+
message = dup.first
|
61
|
+
if String === req.send_request(message, message.last)
|
62
|
+
dup.shift
|
63
|
+
EM.next_tick cb
|
64
|
+
else
|
65
|
+
EM.add_timer 0.1, cb
|
66
|
+
end
|
67
|
+
end
|
68
|
+
}
|
69
|
+
cb.call
|
70
|
+
}
|
71
|
+
}
|
72
|
+
thrd.join
|
73
|
+
end
|
74
|
+
(req.incoming_queue - messages).must_be_empty
|
75
|
+
(messages - req.incoming_queue).must_be_empty
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe EM::Protocols::Zmq2::Req do
|
80
|
+
class MyReq < EM::Protocols::Zmq2::Req
|
81
|
+
attr :incoming_queue, :canceled_requests
|
82
|
+
def initialize(opts={}, defered_conn, defered_mess)
|
83
|
+
super opts
|
84
|
+
@defered_conn = defered_conn
|
85
|
+
@defered_mess = defered_mess
|
86
|
+
@incoming_queue = []
|
87
|
+
@canceled_requests = []
|
88
|
+
end
|
89
|
+
def peer_free(peer_identity, connection)
|
90
|
+
super
|
91
|
+
@defered_conn.succeed
|
92
|
+
end
|
93
|
+
def receive_reply(message, data, request_id)
|
94
|
+
message.first.must_equal 'world'
|
95
|
+
message.last.must_equal data.to_s
|
96
|
+
@incoming_queue << ['hello', message.last]
|
97
|
+
@defered_mess.succeed if message.last == 'xxx'
|
98
|
+
end
|
99
|
+
def cancel_request(request_id)
|
100
|
+
@canceled_requests << request_id
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
let(:finished){ EM::DefaultDeferrable.new }
|
105
|
+
attr :req
|
106
|
+
before do
|
107
|
+
@req = MyReq.new({identity: 'REQ'}, connected, finished)
|
108
|
+
@req.connect(Native::ZBIND_ADDR)
|
109
|
+
end
|
110
|
+
let(:messages){
|
111
|
+
5000.times.map{|i| ['hello', i.to_s]} << ['hello', 'xxx']
|
112
|
+
}
|
113
|
+
|
114
|
+
it 'should send a lot of requests' do
|
115
|
+
Native.with_socket('REP') do |zrep|
|
116
|
+
thrd = Thread.new do
|
117
|
+
messages.size.times do
|
118
|
+
ar = []
|
119
|
+
zrep.recv_strings ar
|
120
|
+
ar[0] = 'world'
|
121
|
+
zrep.send_strings ar
|
122
|
+
end
|
123
|
+
end
|
124
|
+
EM.run {
|
125
|
+
connected.callback {
|
126
|
+
messages.each{|message|
|
127
|
+
req.send_request(message, message.last)
|
128
|
+
}
|
129
|
+
}
|
130
|
+
finished.callback {
|
131
|
+
EM.next_tick{ EM.stop }
|
132
|
+
}
|
133
|
+
}
|
134
|
+
thrd.join
|
135
|
+
end
|
136
|
+
(req.incoming_queue - messages).must_be_empty
|
137
|
+
(messages - req.incoming_queue).must_be_empty
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should not accept message on low hwm with strategy :drop_last" do
|
141
|
+
req.hwm = 2
|
142
|
+
req.hwm_strategy = :drop_last
|
143
|
+
EM.run {
|
144
|
+
req.send_request(['hi', 'ho1'], nil).must_be_kind_of String
|
145
|
+
req.send_request(['hi', 'ho2'], nil).must_be_kind_of String
|
146
|
+
req.send_request(['hi', 'ho3'], nil).wont_be_kind_of String
|
147
|
+
EM.stop
|
148
|
+
}
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should cancel earlier message on low hwm with strategy :drop_first" do
|
152
|
+
req.hwm = 2
|
153
|
+
req.hwm_strategy = :drop_first
|
154
|
+
first_req = nil
|
155
|
+
EM.run {
|
156
|
+
first_req = req.send_request(['hi', 'ho1'], nil)
|
157
|
+
first_req.must_be_kind_of String
|
158
|
+
req.send_request(['hi', 'ho2'], nil).must_be_kind_of String
|
159
|
+
req.send_request(['hi', 'ho3'], nil).must_be_kind_of String
|
160
|
+
EM.stop
|
161
|
+
}
|
162
|
+
req.canceled_requests.must_equal [first_req]
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
describe EM::Protocols::Zmq2::ReqDefer do
|
167
|
+
class TSTRep < EM::Protocols::Zmq2::Rep
|
168
|
+
include DeferredMixin
|
169
|
+
def receive_request(message, environment)
|
170
|
+
send_reply([message.first, 'yeah'], environment)
|
171
|
+
end
|
172
|
+
def peer_free(peer, conn)
|
173
|
+
super
|
174
|
+
@connected.succeed
|
175
|
+
end
|
176
|
+
end
|
177
|
+
it "should correctly setup and call deferrable" do
|
178
|
+
req = EM::Protocols::Zmq2::ReqDefer.new
|
179
|
+
def req.send_message(message, even = false)
|
180
|
+
res = super
|
181
|
+
res
|
182
|
+
end
|
183
|
+
rep = TSTRep.new(connected: connected)
|
184
|
+
rep.bind('inproc://tst')
|
185
|
+
first_success, first_error = nil, nil
|
186
|
+
second_success, second_error = nil, nil
|
187
|
+
require 'pp'
|
188
|
+
EM.run {
|
189
|
+
uniq = Object.new.freeze
|
190
|
+
first = nil
|
191
|
+
follow = proc do |null, data|
|
192
|
+
data.must_equal uniq
|
193
|
+
null.must_be_nil
|
194
|
+
req.connect('inproc://tst')
|
195
|
+
connected.callback do
|
196
|
+
stop = proc{ EM.next_tick{ EM.stop } }
|
197
|
+
second = req.send_request(['hi', 'ho'], uniq) do |reply, data|
|
198
|
+
second_success = true
|
199
|
+
reply.must_equal ['hi', 'yeah']
|
200
|
+
data.must_equal uniq
|
201
|
+
end
|
202
|
+
second.must_be_kind_of EM::Deferrable
|
203
|
+
second.errback do
|
204
|
+
second_error = true
|
205
|
+
end
|
206
|
+
second.callback &stop
|
207
|
+
second.errback &stop
|
208
|
+
end
|
209
|
+
end
|
210
|
+
first = req.send_request(['hi', 'ho'], uniq) do |reply, data|
|
211
|
+
first_success = true
|
212
|
+
reply.must_equal ['hi', 'yeah']
|
213
|
+
data.must_equal uniq
|
214
|
+
end
|
215
|
+
first.must_be_kind_of EM::Deferrable
|
216
|
+
first.timeout(0.3, 1, uniq)
|
217
|
+
first.errback do
|
218
|
+
first_error = true
|
219
|
+
end
|
220
|
+
first.callback &follow
|
221
|
+
first.errback &follow
|
222
|
+
}
|
223
|
+
first_success.must_equal nil
|
224
|
+
first_error.must_equal true
|
225
|
+
second_success.must_equal true
|
226
|
+
second_error.must_equal nil
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
@@ -0,0 +1,221 @@
|
|
1
|
+
require 'eventmachine'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require File.expand_path('../helper.rb', __FILE__)
|
4
|
+
|
5
|
+
require 'em/protocols/zmq2/router'
|
6
|
+
|
7
|
+
describe 'Router' do
|
8
|
+
|
9
|
+
let(:connected) do
|
10
|
+
EM::DefaultDeferrable.new
|
11
|
+
end
|
12
|
+
|
13
|
+
let(:finished) do
|
14
|
+
EM::DefaultDeferrable.new
|
15
|
+
end
|
16
|
+
|
17
|
+
class DealerCollector
|
18
|
+
attr :res_a, :res_b
|
19
|
+
def initialize(till)
|
20
|
+
@till = till
|
21
|
+
@res_a, @res_b = [], []
|
22
|
+
end
|
23
|
+
def full?
|
24
|
+
@res_a.size + @res_b.size >= @till
|
25
|
+
end
|
26
|
+
def full_res
|
27
|
+
@res_a + @res_b
|
28
|
+
end
|
29
|
+
def set_sockets(zbind, zconnect)
|
30
|
+
@zbind = zbind
|
31
|
+
@zconnect = zconnect
|
32
|
+
end
|
33
|
+
def thread
|
34
|
+
Thread.new do
|
35
|
+
begin
|
36
|
+
result = []
|
37
|
+
until full?
|
38
|
+
while @zbind.recv_strings(result, ZMQ::NOBLOCK) != -1
|
39
|
+
result.first.must_equal 'hello'
|
40
|
+
@res_a << result
|
41
|
+
result = []
|
42
|
+
end
|
43
|
+
while @zconnect.recv_strings(result, ZMQ::NOBLOCK) != -1
|
44
|
+
result.first.must_equal 'hello'
|
45
|
+
@res_b << result
|
46
|
+
result = []
|
47
|
+
end
|
48
|
+
sleep(0.01)
|
49
|
+
end
|
50
|
+
rescue
|
51
|
+
puts $!
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe EM::Protocols::Zmq2::PreRouter do
|
58
|
+
class MyPreRouter < EM::Protocols::Zmq2::PreRouter
|
59
|
+
attr :incoming_queue
|
60
|
+
def initialize(connected, finished, opts={})
|
61
|
+
super opts
|
62
|
+
@connected = connected
|
63
|
+
@finished = finished
|
64
|
+
@incoming_queue = {}
|
65
|
+
end
|
66
|
+
def peer_free(peer_ident, connection)
|
67
|
+
super
|
68
|
+
@connected.succeed if @free_peers.size == 2
|
69
|
+
end
|
70
|
+
def receive_message(message)
|
71
|
+
(@incoming_queue[message.first] ||= []) << message[1..-1]
|
72
|
+
@finished.succeed if message.last == 'xxx'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
attr :router
|
77
|
+
before do
|
78
|
+
@router = MyPreRouter.new(connected, finished, identity: 'MyRouter')
|
79
|
+
@router.bind(Native::ZCONNECT_ADDR)
|
80
|
+
@router.connect(Native::ZBIND_ADDR)
|
81
|
+
end
|
82
|
+
|
83
|
+
let(:messages) do
|
84
|
+
62.times.map{|n| ['hello', n.to_s] } << ['hello', 'xxx']
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should be able to receive messages" do
|
88
|
+
halves = messages[0...(messages.size/2)], messages[(messages.size/2)..-1]
|
89
|
+
Native.with_socket_pair('DEALER') do |zbind, zconnect|
|
90
|
+
EM.run {
|
91
|
+
connected.callback do
|
92
|
+
halves[0].each do |message|
|
93
|
+
zbind.send_strings(message)
|
94
|
+
end
|
95
|
+
halves[1].each do |message|
|
96
|
+
zconnect.send_strings(message)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
finished.callback do
|
100
|
+
EM.next_tick{ EM.stop }
|
101
|
+
end
|
102
|
+
}
|
103
|
+
end
|
104
|
+
router.incoming_queue['BIND_DEALER'].must_equal halves[0]
|
105
|
+
router.incoming_queue['CONNECT_DEALER'].must_equal halves[1]
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should be able to route messages" do
|
109
|
+
collector = DealerCollector.new(messages.size)
|
110
|
+
halves = messages[0...(messages.size/2)], messages[(messages.size/2)..-1]
|
111
|
+
Native.with_socket_pair('DEALER') do |zbind, zconnect|
|
112
|
+
collector.set_sockets zbind, zconnect
|
113
|
+
thrd = collector.thread
|
114
|
+
EM.run {
|
115
|
+
dup_halves = halves.map(&:dup)
|
116
|
+
connected.callback do
|
117
|
+
dup_halves[0].each do |message|
|
118
|
+
router.send_message(['BIND_DEALER', *message]).must_equal true
|
119
|
+
end
|
120
|
+
dup_halves[1].each do |message|
|
121
|
+
router.send_message(['CONNECT_DEALER', *message]).must_equal true
|
122
|
+
end
|
123
|
+
EM.defer(proc do thrd.join end, proc do
|
124
|
+
EM.next_tick{ EM.stop }
|
125
|
+
end)
|
126
|
+
end
|
127
|
+
}
|
128
|
+
end
|
129
|
+
collector.res_a.must_equal halves[0]
|
130
|
+
collector.res_b.must_equal halves[1]
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe EM::Protocols::Zmq2::Router do
|
135
|
+
class MyRouter < EM::Protocols::Zmq2::Router
|
136
|
+
attr :incoming_queue, :canceled_messages
|
137
|
+
def initialize(connected, finished, opts={})
|
138
|
+
super opts
|
139
|
+
@connected = connected
|
140
|
+
@finished = finished
|
141
|
+
@incoming_queue = {}
|
142
|
+
@canceled_messages = []
|
143
|
+
end
|
144
|
+
def peer_free(peer_ident, connection)
|
145
|
+
super
|
146
|
+
@connected.succeed if @free_peers.size == 2
|
147
|
+
end
|
148
|
+
def receive_message(message)
|
149
|
+
(@incoming_queue[message.first] ||= []) << message[1..-1]
|
150
|
+
@finished.succeed if message.last == 'xxx'
|
151
|
+
end
|
152
|
+
def cancel_message(message)
|
153
|
+
@canceled_messages << message
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
attr :router
|
158
|
+
before do
|
159
|
+
@router = MyRouter.new(connected, finished, identity: 'MyRouter')
|
160
|
+
@router.bind(Native::ZCONNECT_ADDR)
|
161
|
+
@router.connect(Native::ZBIND_ADDR)
|
162
|
+
end
|
163
|
+
|
164
|
+
let(:messages) do
|
165
|
+
10000.times.map{|n| ['hello', n.to_s] } << ['hello', 'xxx']
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should be able to route a lot of messages" do
|
169
|
+
collector = DealerCollector.new(messages.size)
|
170
|
+
halves = messages[0...(messages.size/2)], messages[(messages.size/2)..-1]
|
171
|
+
Native.with_socket_pair('DEALER') do |zbind, zconnect|
|
172
|
+
collector.set_sockets zbind, zconnect
|
173
|
+
thrd = collector.thread
|
174
|
+
EM.run {
|
175
|
+
dup_halves = halves.map(&:dup)
|
176
|
+
connected.callback do
|
177
|
+
dup_halves[0].each do |message|
|
178
|
+
router.send_message(['BIND_DEALER', *message])
|
179
|
+
end
|
180
|
+
dup_halves[1].each do |message|
|
181
|
+
router.send_message(['CONNECT_DEALER', *message])
|
182
|
+
end
|
183
|
+
EM.defer(proc do thrd.join end, proc do
|
184
|
+
EM.next_tick{ EM.stop }
|
185
|
+
end)
|
186
|
+
end
|
187
|
+
}
|
188
|
+
thrd.join
|
189
|
+
end
|
190
|
+
collector.res_a.must_equal halves[0]
|
191
|
+
collector.res_b.must_equal halves[1]
|
192
|
+
end
|
193
|
+
|
194
|
+
it "should not accept message on low hwm with strategy :drop_last" do
|
195
|
+
router.hwm = 1
|
196
|
+
router.hwm_strategy = :drop_last
|
197
|
+
EM.run {
|
198
|
+
router.send_message(['FIRST_PEER', 'hi', 'ho1']).must_equal true
|
199
|
+
router.send_message(['FIRST_PEER', 'hi', 'ho2']).wont_equal true
|
200
|
+
router.send_message(['SECOND_PEER', 'hi', 'ho1']).must_equal true
|
201
|
+
router.send_message(['SECOND_PEER', 'hi', 'ho2']).wont_equal true
|
202
|
+
EM.stop
|
203
|
+
}
|
204
|
+
end
|
205
|
+
|
206
|
+
it "should cancel earlier message on low hwm with strategy :drop_first" do
|
207
|
+
router.hwm = 1
|
208
|
+
router.hwm_strategy = :drop_first
|
209
|
+
EM.run {
|
210
|
+
router.send_message(['FIRST_PEER', 'hi', 'ho1']).must_equal true
|
211
|
+
router.send_message(['FIRST_PEER', 'hi', 'ho2']).must_equal true
|
212
|
+
router.send_message(['SECOND_PEER', 'hi', 'ho1']).must_equal true
|
213
|
+
router.send_message(['SECOND_PEER', 'hi', 'ho2']).must_equal true
|
214
|
+
EM.stop
|
215
|
+
}
|
216
|
+
router.canceled_messages.count.must_equal 2
|
217
|
+
router.canceled_messages.must_include ['FIRST_PEER', 'hi', 'ho1']
|
218
|
+
router.canceled_messages.must_include ['SECOND_PEER', 'hi', 'ho1']
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|