ione-rpc 1.0.0.pre4 → 1.0.0
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.
- checksums.yaml +4 -4
- data/lib/ione/rpc/client.rb +31 -11
- data/lib/ione/rpc/client_peer.rb +20 -3
- data/lib/ione/rpc/peer.rb +4 -0
- data/lib/ione/rpc/server.rb +2 -1
- data/lib/ione/rpc/version.rb +1 -1
- data/lib/ione/rpc.rb +3 -0
- data/spec/ione/rpc/client_peer_spec.rb +28 -3
- data/spec/ione/rpc/client_spec.rb +23 -3
- data/spec/ione/rpc/peer_common.rb +15 -0
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 518c9857895955f9c26c4be3d3be5d21773c7525
|
4
|
+
data.tar.gz: 6b6c39ffa664e4b290bb5c0ebaeab462dd8fbb23
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d3e6c4d47dda87d60ac7034243d0c946af0117bd8fed3b043d23ecbbbc6cb6817253e3b5199bb5967d38b077d51ed40a4991d04de29e93cd7adbb0e12098427e
|
7
|
+
data.tar.gz: 9f60335dcdb60a2353fcf07684fdd9e9f17715c679253badb1f6415e4e276de67759bfe427392e48266db2216d7a7be3a816dbb2543e6eeb9152e53c702926bb
|
data/lib/ione/rpc/client.rb
CHANGED
@@ -179,31 +179,34 @@ module Ione
|
|
179
179
|
# error response – that is protocol specific and up to the implementation
|
180
180
|
# to handle), or when there was no connection open.
|
181
181
|
def send_request(request, connection=nil, timeout=nil)
|
182
|
-
|
182
|
+
if connection
|
183
|
+
chosen_connection = connection
|
184
|
+
else
|
183
185
|
@lock.lock
|
184
186
|
begin
|
185
|
-
|
187
|
+
chosen_connection = choose_connection(@connections, request)
|
186
188
|
ensure
|
187
189
|
@lock.unlock
|
188
190
|
end
|
189
191
|
end
|
190
|
-
if
|
191
|
-
f =
|
192
|
+
if chosen_connection && !chosen_connection.closed?
|
193
|
+
f = chosen_connection.send_message(request, timeout)
|
192
194
|
f = f.fallback do |error|
|
193
|
-
if error.is_a?(
|
195
|
+
if error.is_a?(Rpc::ConnectionClosedError)
|
194
196
|
@logger.warn('Request failed because the connection closed, retrying') if @logger
|
195
|
-
send_request(request)
|
197
|
+
send_request(request, connection, timeout)
|
196
198
|
else
|
197
|
-
|
199
|
+
Ione::Future.failed(error)
|
198
200
|
end
|
199
201
|
end
|
200
202
|
f.on_failure do |error|
|
201
203
|
@logger.warn('Request failed: %s' % error.message) if @logger
|
202
204
|
end
|
203
205
|
f
|
206
|
+
elsif chosen_connection
|
207
|
+
Future.failed(Rpc::RequestNotSentError.new('Not connected'))
|
204
208
|
else
|
205
|
-
|
206
|
-
Future.failed(Io::ConnectionError.new('Not connected'))
|
209
|
+
Future.failed(Rpc::NoConnectionError.new('No connection'))
|
207
210
|
end
|
208
211
|
rescue => e
|
209
212
|
Future.failed(e)
|
@@ -252,6 +255,19 @@ module Ione
|
|
252
255
|
connections.sample
|
253
256
|
end
|
254
257
|
|
258
|
+
# Override this method to control if, and how many times, the client should
|
259
|
+
# attempt to reconnect on connection failures.
|
260
|
+
#
|
261
|
+
# You can, for example, stop reconnecting after a certain number of attempts.
|
262
|
+
#
|
263
|
+
# @param [String] host the host to connect to
|
264
|
+
# @param [Integer] port the port to connect to
|
265
|
+
# @param [Integer] attempts the number of attempts that have been made so
|
266
|
+
# far – when 1 or above a connection attempt has just failed, when 0
|
267
|
+
# an open connection was abruptly closed and the question is whether or
|
268
|
+
# not to attempt to connect again.
|
269
|
+
# @return [Boolean] `true` if a connection attempt should be made, `false`
|
270
|
+
# otherwise.
|
255
271
|
def reconnect?(host, port, attempts)
|
256
272
|
true
|
257
273
|
end
|
@@ -288,7 +304,7 @@ module Ione
|
|
288
304
|
else
|
289
305
|
@logger.info('Not reconnecting to %s:%d' % [host, port]) if @logger
|
290
306
|
remove_host(host, port)
|
291
|
-
|
307
|
+
Ione::Future.failed(e)
|
292
308
|
end
|
293
309
|
end
|
294
310
|
f.flat_map do |connection|
|
@@ -326,7 +342,11 @@ module Ione
|
|
326
342
|
@logger.info(message) if @logger
|
327
343
|
end
|
328
344
|
@lock.synchronize { @connections.delete(connection) }
|
329
|
-
|
345
|
+
if error && reconnect?(connection.host, connection.port, 0)
|
346
|
+
connect(connection.host, connection.port)
|
347
|
+
else
|
348
|
+
remove_host(connection.host, connection.port)
|
349
|
+
end
|
330
350
|
end
|
331
351
|
|
332
352
|
def normalize_address(host, port)
|
data/lib/ione/rpc/client_peer.rb
CHANGED
@@ -36,6 +36,9 @@ module Ione
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def send_message(request, timeout=nil)
|
39
|
+
if closed?
|
40
|
+
return Ione::Future.failed(Rpc::RequestNotSentError.new('Connection closed'))
|
41
|
+
end
|
39
42
|
promise = Ione::Promise.new
|
40
43
|
channel = nil
|
41
44
|
@lock.lock
|
@@ -117,9 +120,23 @@ module Ione
|
|
117
120
|
end
|
118
121
|
|
119
122
|
def handle_closed(cause=nil)
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
+
in_flight_promises = nil
|
124
|
+
queued_promises = nil
|
125
|
+
@lock.lock
|
126
|
+
begin
|
127
|
+
in_flight_promises = @channels.reject(&:nil?)
|
128
|
+
@channels = [nil] * @channels.size
|
129
|
+
queued_promises = @queue.map(&:last)
|
130
|
+
@queue = []
|
131
|
+
ensure
|
132
|
+
@lock.unlock
|
133
|
+
end
|
134
|
+
message = 'Connection closed'
|
135
|
+
message << ": #{cause.message}" if cause
|
136
|
+
error = Io::ConnectionClosedError.new(message)
|
137
|
+
in_flight_promises.each { |p| p.fail(error) }
|
138
|
+
error = RequestNotSentError.new(message)
|
139
|
+
queued_promises.each { |p| p.fail(error) }
|
123
140
|
super
|
124
141
|
end
|
125
142
|
end
|
data/lib/ione/rpc/peer.rb
CHANGED
data/lib/ione/rpc/server.rb
CHANGED
@@ -107,8 +107,9 @@ module Ione
|
|
107
107
|
|
108
108
|
def setup_server
|
109
109
|
@io_reactor.bind(@bind_address, @port, @queue_length) do |acceptor|
|
110
|
+
@acceptor = acceptor
|
110
111
|
@logger.info('Server listening for connections on %s:%d' % [@bind_address, @port]) if @logger
|
111
|
-
acceptor.on_accept do |connection|
|
112
|
+
@acceptor.on_accept do |connection|
|
112
113
|
@logger.info('Connection from %s:%d accepted' % [connection.host, connection.port]) if @logger
|
113
114
|
peer = ServerPeer.new(connection, @codec, self, @logger)
|
114
115
|
peer.on_closed do
|
data/lib/ione/rpc/version.rb
CHANGED
data/lib/ione/rpc.rb
CHANGED
@@ -59,12 +59,31 @@ module Ione
|
|
59
59
|
include_examples 'peers'
|
60
60
|
|
61
61
|
context 'when the connection closes' do
|
62
|
-
it 'fails all
|
62
|
+
it 'fails all in-flight requests' do
|
63
63
|
f1 = peer.send_message('hello')
|
64
64
|
f2 = peer.send_message('world')
|
65
65
|
connection.closed_listener.call
|
66
|
-
expect { f1.value }.to raise_error(Io::ConnectionClosedError)
|
67
|
-
expect { f2.value }.to raise_error(Io::ConnectionClosedError)
|
66
|
+
expect { f1.value }.to raise_error(Io::ConnectionClosedError, /connection closed/i)
|
67
|
+
expect { f2.value }.to raise_error(Io::ConnectionClosedError, /connection closed/i)
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'includes the error message from the cause when there is one' do
|
71
|
+
f = peer.send_message('hello')
|
72
|
+
connection.closed_listener.call(StandardError.new('foo'))
|
73
|
+
expect { f.value }.to raise_error(Io::ConnectionClosedError, /connection closed: foo/i)
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'fails queued requests' do
|
77
|
+
fs = Array.new(max_channels + 2) { peer.send_message('foo') }
|
78
|
+
connection.closed_listener.call
|
79
|
+
expect { fs[0].value }.to raise_error(Io::ConnectionClosedError)
|
80
|
+
expect { fs[max_channels].value }.to raise_error(Io::ConnectionClosedError)
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'fails queued messages with an error that shows that the request was never sent' do
|
84
|
+
fs = Array.new(max_channels + 2) { peer.send_message('foo') }
|
85
|
+
connection.closed_listener.call
|
86
|
+
expect { fs[max_channels].value }.to raise_error(Rpc::RequestNotSentError)
|
68
87
|
end
|
69
88
|
end
|
70
89
|
|
@@ -127,6 +146,12 @@ module Ione
|
|
127
146
|
expect { f.value }.to_not raise_error
|
128
147
|
end
|
129
148
|
|
149
|
+
it 'fails the request when the connection is closed' do
|
150
|
+
connection.stub(:closed?).and_return(true)
|
151
|
+
f = peer.send_message('foo', 2)
|
152
|
+
expect { f.value }.to raise_error(Rpc::RequestNotSentError)
|
153
|
+
end
|
154
|
+
|
130
155
|
context 'with a non-recoding codec' do
|
131
156
|
let :codec do
|
132
157
|
double(:codec, recoding?: false)
|
@@ -53,7 +53,8 @@ module Ione
|
|
53
53
|
connection.stub(:on_data)
|
54
54
|
connection.stub(:on_closed)
|
55
55
|
connection.stub(:write)
|
56
|
-
connection.stub(:close)
|
56
|
+
connection.stub(:close) { connection.stub(:closed?).and_return(true) }
|
57
|
+
connection.stub(:closed?).and_return(false)
|
57
58
|
connection
|
58
59
|
end
|
59
60
|
|
@@ -214,7 +215,7 @@ module Ione
|
|
214
215
|
|
215
216
|
it 'returns a failed future when called when not connected' do
|
216
217
|
client.stop.value
|
217
|
-
expect { client.send_request('PING').value }.to raise_error(
|
218
|
+
expect { client.send_request('PING').value }.to raise_error(Rpc::NoConnectionError)
|
218
219
|
end
|
219
220
|
end
|
220
221
|
|
@@ -274,13 +275,24 @@ module Ione
|
|
274
275
|
expect { f.value }.to raise_error('Bork')
|
275
276
|
end
|
276
277
|
|
278
|
+
it 'fails the request when #choose_connection returns a closed connection' do
|
279
|
+
client.override_choose_connection do |connections, request|
|
280
|
+
c = connections.first
|
281
|
+
c.close
|
282
|
+
c
|
283
|
+
end
|
284
|
+
client.start.value
|
285
|
+
f = client.send_request('PING')
|
286
|
+
expect { f.value }.to raise_error(Rpc::RequestNotSentError)
|
287
|
+
end
|
288
|
+
|
277
289
|
it 'fails the request when #choose_connection returns nil' do
|
278
290
|
client.override_choose_connection do |connections, request|
|
279
291
|
nil
|
280
292
|
end
|
281
293
|
client.start.value
|
282
294
|
f = client.send_request('PING')
|
283
|
-
expect { f.value }.to raise_error(
|
295
|
+
expect { f.value }.to raise_error(Rpc::NoConnectionError)
|
284
296
|
end
|
285
297
|
end
|
286
298
|
end
|
@@ -510,6 +522,14 @@ module Ione
|
|
510
522
|
connection_attempts_by_host['node1.example.com'].should == 10
|
511
523
|
connection_attempts_by_host['node2.example.com'].should == 1
|
512
524
|
end
|
525
|
+
|
526
|
+
it 'allows the connection to be manually reconnected' do
|
527
|
+
client.start.value
|
528
|
+
c1 = client.created_connections.find { |c| c.host == 'node1.example.com' }
|
529
|
+
c1.closed_listener.call
|
530
|
+
client.add_host(c1.host, c1.port).value
|
531
|
+
io_reactor.should have_received(:connect).with('node1.example.com', anything, anything).twice
|
532
|
+
end
|
513
533
|
end
|
514
534
|
|
515
535
|
context 'with multiple connections' do
|
@@ -120,6 +120,15 @@ shared_examples 'peers' do
|
|
120
120
|
connection.should have_received(:close)
|
121
121
|
end
|
122
122
|
end
|
123
|
+
|
124
|
+
describe '#closed?' do
|
125
|
+
it 'reflects the underlying connection\'s state' do
|
126
|
+
connection.stub(:closed?).and_return(true)
|
127
|
+
peer.should be_closed
|
128
|
+
connection.stub(:closed?).and_return(false)
|
129
|
+
peer.should_not be_closed
|
130
|
+
end
|
131
|
+
end
|
123
132
|
end
|
124
133
|
|
125
134
|
module RpcSpec
|
@@ -130,10 +139,16 @@ module RpcSpec
|
|
130
139
|
@host = 'example.com'
|
131
140
|
@port = 9999
|
132
141
|
@written_bytes = ''
|
142
|
+
@closed = false
|
143
|
+
end
|
144
|
+
|
145
|
+
def closed?
|
146
|
+
@closed
|
133
147
|
end
|
134
148
|
|
135
149
|
def close(cause=nil)
|
136
150
|
@closed_listener.call(cause) if @closed_listener
|
151
|
+
@closed = true
|
137
152
|
end
|
138
153
|
|
139
154
|
def write(bytes)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ione-rpc
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.0
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Theo Hultberg
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-08-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ione
|
@@ -61,9 +61,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
61
61
|
version: 1.9.3
|
62
62
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
63
|
requirements:
|
64
|
-
- - '
|
64
|
+
- - '>='
|
65
65
|
- !ruby/object:Gem::Version
|
66
|
-
version:
|
66
|
+
version: '0'
|
67
67
|
requirements: []
|
68
68
|
rubyforge_project:
|
69
69
|
rubygems_version: 2.2.1
|