bones-rpc 0.0.2 → 0.0.3
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/.ruby-gemset +1 -1
- data/.ruby-version +1 -1
- data/bones-rpc.gemspec +1 -4
- data/lib/bones/rpc.rb +1 -1
- data/lib/bones/rpc/adapter.rb +44 -4
- data/lib/bones/rpc/adapter/json.rb +66 -0
- data/lib/bones/rpc/address.rb +6 -4
- data/lib/bones/rpc/backend.rb +31 -0
- data/lib/bones/rpc/backend/base.rb +30 -0
- data/lib/bones/rpc/backend/synchronous.rb +29 -0
- data/lib/bones/rpc/cluster.rb +18 -18
- data/lib/bones/rpc/connection.rb +19 -15
- data/lib/bones/rpc/connection/socket.rb +0 -2
- data/lib/bones/rpc/connection/socket/connectable.rb +15 -11
- data/lib/bones/rpc/context.rb +2 -2
- data/lib/bones/rpc/dns_resolver.rb +85 -0
- data/lib/bones/rpc/errors.rb +3 -0
- data/lib/bones/rpc/failover.rb +3 -3
- data/lib/bones/rpc/failover/disconnect.rb +2 -2
- data/lib/bones/rpc/failover/ignore.rb +2 -2
- data/lib/bones/rpc/failover/retry.rb +2 -2
- data/lib/bones/rpc/instrumentable.rb +3 -3
- data/lib/bones/rpc/instrumentable/log.rb +2 -2
- data/lib/bones/rpc/instrumentable/noop.rb +2 -2
- data/lib/bones/rpc/loggable.rb +8 -8
- data/lib/bones/rpc/node.rb +47 -37
- data/lib/bones/rpc/node/registry.rb +4 -0
- data/lib/bones/rpc/parser.rb +16 -5
- data/lib/bones/rpc/parser/buffer.rb +6 -2
- data/lib/bones/rpc/protocol/adapter_helper.rb +2 -2
- data/lib/bones/rpc/protocol/binary_helper.rb +2 -2
- data/lib/bones/rpc/read_preference.rb +3 -3
- data/lib/bones/rpc/read_preference/nearest.rb +3 -3
- data/lib/bones/rpc/read_preference/selectable.rb +4 -4
- data/lib/bones/rpc/readable.rb +4 -4
- data/lib/bones/rpc/session.rb +25 -16
- data/lib/bones/rpc/synchronous.rb +2 -0
- data/lib/bones/rpc/synchronous/connection.rb +36 -0
- data/lib/bones/rpc/synchronous/connection/reader.rb +59 -0
- data/lib/bones/rpc/synchronous/connection/socket.rb +4 -0
- data/lib/bones/rpc/synchronous/connection/socket/ssl.rb +57 -0
- data/lib/bones/rpc/synchronous/connection/socket/tcp.rb +30 -0
- data/lib/bones/rpc/synchronous/connection/writer.rb +86 -0
- data/lib/bones/rpc/synchronous/future.rb +91 -0
- data/lib/bones/rpc/synchronous/node.rb +45 -0
- data/lib/bones/rpc/uri.rb +20 -20
- data/lib/bones/rpc/version.rb +1 -1
- metadata +16 -52
- data/lib/bones/rpc/adapter/erlang.rb +0 -28
- data/lib/bones/rpc/adapter/msgpack.rb +0 -52
- data/lib/bones/rpc/connection/reader.rb +0 -49
- data/lib/bones/rpc/connection/socket/ssl.rb +0 -35
- data/lib/bones/rpc/connection/socket/tcp.rb +0 -28
- data/lib/bones/rpc/connection/writer.rb +0 -51
- data/lib/bones/rpc/future.rb +0 -26
data/lib/bones/rpc/loggable.rb
CHANGED
@@ -4,7 +4,7 @@ module Bones
|
|
4
4
|
|
5
5
|
# Contains behaviour for logging.
|
6
6
|
#
|
7
|
-
# @since
|
7
|
+
# @since 0.0.1
|
8
8
|
module Loggable
|
9
9
|
|
10
10
|
# Log the provided operations.
|
@@ -16,7 +16,7 @@ module Bones
|
|
16
16
|
# @param [ Array ] ops The operations.
|
17
17
|
# @param [ String ] runtime The runtime in formatted ms.
|
18
18
|
#
|
19
|
-
# @since
|
19
|
+
# @since 0.0.1
|
20
20
|
def self.log_operations(prefix, ops, runtime)
|
21
21
|
indent = " "*prefix.length
|
22
22
|
if ops.length == 1
|
@@ -38,7 +38,7 @@ module Bones
|
|
38
38
|
# @param [ String ] payload The log operations.
|
39
39
|
# @param [ String ] runtime The runtime in formatted ms.
|
40
40
|
#
|
41
|
-
# @since
|
41
|
+
# @since 0.0.1
|
42
42
|
def self.debug(prefix, payload, runtime)
|
43
43
|
Bones::RPC.logger.debug([ prefix, payload, "runtime: #{runtime}" ].join(' '))
|
44
44
|
end
|
@@ -52,7 +52,7 @@ module Bones
|
|
52
52
|
# @param [ String ] payload The log operations.
|
53
53
|
# @param [ String ] runtime The runtime in formatted ms.
|
54
54
|
#
|
55
|
-
# @since
|
55
|
+
# @since 0.0.1
|
56
56
|
def self.warn(prefix, payload, runtime)
|
57
57
|
Bones::RPC.logger.warn([ prefix, payload, "runtime: #{runtime}" ].join(' '))
|
58
58
|
end
|
@@ -64,7 +64,7 @@ module Bones
|
|
64
64
|
#
|
65
65
|
# @return [ Logger ] The logger.
|
66
66
|
#
|
67
|
-
# @since
|
67
|
+
# @since 0.0.1
|
68
68
|
def logger
|
69
69
|
return @logger if defined?(@logger)
|
70
70
|
@logger = rails_logger || default_logger
|
@@ -77,7 +77,7 @@ module Bones
|
|
77
77
|
#
|
78
78
|
# @return [ Logger ] The Rails logger.
|
79
79
|
#
|
80
|
-
# @since
|
80
|
+
# @since 0.0.1
|
81
81
|
def rails_logger
|
82
82
|
defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger
|
83
83
|
end
|
@@ -89,7 +89,7 @@ module Bones
|
|
89
89
|
#
|
90
90
|
# @return [ Logger ] The default logger.
|
91
91
|
#
|
92
|
-
# @since
|
92
|
+
# @since 0.0.1
|
93
93
|
def default_logger
|
94
94
|
logger = Logger.new(STDOUT)
|
95
95
|
logger.level = Logger::INFO
|
@@ -103,7 +103,7 @@ module Bones
|
|
103
103
|
#
|
104
104
|
# @return [ Logger ] The logger.
|
105
105
|
#
|
106
|
-
# @since
|
106
|
+
# @since 0.0.1
|
107
107
|
def logger=(logger)
|
108
108
|
@logger = logger
|
109
109
|
end
|
data/lib/bones/rpc/node.rb
CHANGED
@@ -2,7 +2,6 @@
|
|
2
2
|
require 'bones/rpc/address'
|
3
3
|
require 'bones/rpc/connection'
|
4
4
|
require 'bones/rpc/failover'
|
5
|
-
require 'bones/rpc/future'
|
6
5
|
require 'bones/rpc/instrumentable'
|
7
6
|
require 'bones/rpc/node/registry'
|
8
7
|
|
@@ -11,9 +10,8 @@ module Bones
|
|
11
10
|
|
12
11
|
# Represents a client to a node in a server cluster.
|
13
12
|
#
|
14
|
-
# @since
|
13
|
+
# @since 0.0.1
|
15
14
|
class Node
|
16
|
-
include Celluloid
|
17
15
|
include Instrumentable
|
18
16
|
|
19
17
|
# @!attribute address
|
@@ -37,15 +35,15 @@ module Bones
|
|
37
35
|
#
|
38
36
|
# @return [ true, false ] If the addresses are equal.
|
39
37
|
#
|
40
|
-
# @since
|
38
|
+
# @since 0.0.1
|
41
39
|
def ==(other)
|
42
40
|
return false unless other.is_a?(Node)
|
43
|
-
|
41
|
+
address.resolved == other.address.resolved
|
44
42
|
end
|
45
43
|
alias :eql? :==
|
46
44
|
|
47
45
|
def adapter
|
48
|
-
@adapter ||= Adapter.get(options[:adapter] || :
|
46
|
+
@adapter ||= Adapter.get(options[:adapter] || :json)
|
49
47
|
end
|
50
48
|
|
51
49
|
def attach(channel, id, future)
|
@@ -65,10 +63,10 @@ module Bones
|
|
65
63
|
#
|
66
64
|
# @return [ true ] If the connection suceeded.
|
67
65
|
#
|
68
|
-
# @since
|
66
|
+
# @since 0.0.1
|
69
67
|
def connect
|
70
68
|
start = Time.now
|
71
|
-
|
69
|
+
connection { |conn| conn.connect }
|
72
70
|
@latency = Time.now - start
|
73
71
|
@down_at = nil
|
74
72
|
true
|
@@ -81,9 +79,17 @@ module Bones
|
|
81
79
|
#
|
82
80
|
# @return [ true, false ] If the node is connected or not.
|
83
81
|
#
|
84
|
-
# @since
|
82
|
+
# @since 0.0.1
|
85
83
|
def connected?
|
86
|
-
|
84
|
+
connection { |conn| conn.alive? }
|
85
|
+
end
|
86
|
+
|
87
|
+
def connection
|
88
|
+
if block_given?
|
89
|
+
yield @connection
|
90
|
+
else
|
91
|
+
@connection
|
92
|
+
end
|
87
93
|
end
|
88
94
|
|
89
95
|
def detach(channel, id)
|
@@ -97,9 +103,9 @@ module Bones
|
|
97
103
|
#
|
98
104
|
# @return [ true ] If the disconnection succeeded.
|
99
105
|
#
|
100
|
-
# @since
|
106
|
+
# @since 0.0.1
|
101
107
|
def disconnect
|
102
|
-
|
108
|
+
connection { |conn| conn.disconnect }
|
103
109
|
true
|
104
110
|
end
|
105
111
|
|
@@ -110,7 +116,7 @@ module Bones
|
|
110
116
|
#
|
111
117
|
# @return [ Time, nil ] The time the node went down, or nil if up.
|
112
118
|
#
|
113
|
-
# @since
|
119
|
+
# @since 0.0.1
|
114
120
|
def down?
|
115
121
|
!!@down_at
|
116
122
|
end
|
@@ -122,7 +128,7 @@ module Bones
|
|
122
128
|
#
|
123
129
|
# @return [ nil ] Nothing.
|
124
130
|
#
|
125
|
-
# @since
|
131
|
+
# @since 0.0.1
|
126
132
|
def down
|
127
133
|
@down_at = Time.new
|
128
134
|
@latency = nil
|
@@ -141,7 +147,7 @@ module Bones
|
|
141
147
|
#
|
142
148
|
# @return [ nil ] nil.
|
143
149
|
#
|
144
|
-
# @since
|
150
|
+
# @since 0.0.1
|
145
151
|
def ensure_connected(&block)
|
146
152
|
begin
|
147
153
|
connect unless connected?
|
@@ -162,7 +168,7 @@ module Bones
|
|
162
168
|
def initialize(cluster, address)
|
163
169
|
@cluster = cluster
|
164
170
|
@address = address
|
165
|
-
@connection =
|
171
|
+
@connection = cluster.session.backend.connection_class.new(current_actor)
|
166
172
|
@down_at = nil
|
167
173
|
@refreshed_at = nil
|
168
174
|
@latency = nil
|
@@ -170,7 +176,7 @@ module Bones
|
|
170
176
|
@registry = Node::Registry.new
|
171
177
|
@request_id = 0
|
172
178
|
@synack_id = 0
|
173
|
-
@address.resolve(
|
179
|
+
@address.resolve(current_actor)
|
174
180
|
end
|
175
181
|
|
176
182
|
# Get the node as a nice formatted string.
|
@@ -180,7 +186,7 @@ module Bones
|
|
180
186
|
#
|
181
187
|
# @return [ String ] The string inspection.
|
182
188
|
#
|
183
|
-
# @since
|
189
|
+
# @since 0.0.1
|
184
190
|
def inspect
|
185
191
|
"<#{self.class.name} resolved_address=#{address.resolved.inspect}>"
|
186
192
|
end
|
@@ -194,7 +200,7 @@ module Bones
|
|
194
200
|
#
|
195
201
|
# @return [ true, false] Whether the node needs to be refreshed.
|
196
202
|
#
|
197
|
-
# @since
|
203
|
+
# @since 0.0.1
|
198
204
|
def needs_refresh?(time)
|
199
205
|
!refreshed_at || refreshed_at < time
|
200
206
|
end
|
@@ -220,12 +226,12 @@ module Bones
|
|
220
226
|
#
|
221
227
|
# @return [ nil ] nil.
|
222
228
|
#
|
223
|
-
# @since
|
229
|
+
# @since 0.0.1
|
224
230
|
def refresh
|
225
|
-
if address.resolve(
|
231
|
+
if address.resolve(current_actor)
|
226
232
|
begin
|
227
233
|
@refreshed_at = Time.now
|
228
|
-
if synchronize.value(
|
234
|
+
if synchronize.value(refresh_timeout)
|
229
235
|
cluster.handle_refresh(current_actor)
|
230
236
|
else
|
231
237
|
down
|
@@ -236,24 +242,28 @@ module Bones
|
|
236
242
|
end
|
237
243
|
end
|
238
244
|
|
239
|
-
def request(method, params)
|
240
|
-
with_future(Protocol::Request.new(next_request_id, method, params))
|
241
|
-
end
|
242
|
-
|
243
|
-
def synchronize
|
244
|
-
with_future(Protocol::Synchronize.new(next_synack_id, adapter))
|
245
|
-
end
|
246
|
-
|
247
245
|
# Get the timeout, in seconds, for this node.
|
248
246
|
#
|
249
247
|
# @example Get the timeout in seconds.
|
250
|
-
# node.
|
248
|
+
# node.refresh_timeout
|
251
249
|
#
|
252
250
|
# @return [ Integer ] The configured timeout or the default of 5.
|
253
251
|
#
|
254
|
-
# @since
|
255
|
-
def
|
256
|
-
@
|
252
|
+
# @since 0.0.1
|
253
|
+
def refresh_timeout
|
254
|
+
@refresh_timeout ||= (options[:timeout] || 5)
|
255
|
+
end
|
256
|
+
|
257
|
+
def registry_empty?
|
258
|
+
@registry.empty?
|
259
|
+
end
|
260
|
+
|
261
|
+
def request(method, params)
|
262
|
+
with_future(Protocol::Request.new(next_request_id, method, params))
|
263
|
+
end
|
264
|
+
|
265
|
+
def synchronize
|
266
|
+
with_future(Protocol::Synchronize.new(next_synack_id, adapter))
|
257
267
|
end
|
258
268
|
|
259
269
|
private
|
@@ -271,7 +281,7 @@ module Bones
|
|
271
281
|
#
|
272
282
|
# @return [ Object ] The result of the yield.
|
273
283
|
#
|
274
|
-
# @since
|
284
|
+
# @since 0.0.1
|
275
285
|
def logging(message)
|
276
286
|
instrument(TOPIC, prefix: " BONES-RPC: #{address.resolved}", ops: [message]) do
|
277
287
|
yield if block_given?
|
@@ -297,7 +307,7 @@ module Bones
|
|
297
307
|
def process(message, future = nil)
|
298
308
|
logging(message) do
|
299
309
|
ensure_connected do
|
300
|
-
|
310
|
+
connection { |conn| conn.write([[message, future]]) }
|
301
311
|
end
|
302
312
|
end
|
303
313
|
return future
|
@@ -306,7 +316,7 @@ module Bones
|
|
306
316
|
end
|
307
317
|
|
308
318
|
def with_future(message)
|
309
|
-
process(message,
|
319
|
+
process(message, cluster.session.backend.future_class.new)
|
310
320
|
end
|
311
321
|
|
312
322
|
def without_future(message)
|
@@ -8,6 +8,10 @@ module Bones
|
|
8
8
|
@registry = {}
|
9
9
|
end
|
10
10
|
|
11
|
+
def empty?
|
12
|
+
@registry.empty? || @registry.all? { |channel, child| child.empty? }
|
13
|
+
end
|
14
|
+
|
11
15
|
def flush(exception = Errors::ConnectionFailure.new("Socket closed"))
|
12
16
|
return true if @registry.empty?
|
13
17
|
@registry.each do |channel, futures|
|
data/lib/bones/rpc/parser.rb
CHANGED
@@ -31,29 +31,32 @@ module Bones
|
|
31
31
|
if b.nil?
|
32
32
|
raise EOFError
|
33
33
|
elsif b.start_with?(EXT8)
|
34
|
+
pos = buffer.pos
|
34
35
|
buffer.skip(1)
|
35
36
|
len, = buffer.read(1).unpack('C')
|
36
37
|
type, = buffer.read(1).unpack('C')
|
37
38
|
check_ext!(type)
|
38
39
|
head, = buffer.read(1).unpack('C')
|
39
40
|
data = buffer.read(len-1)
|
40
|
-
parse_ext!(head, data)
|
41
|
+
parse_ext!(head, data, pos)
|
41
42
|
elsif b.start_with?(EXT16)
|
43
|
+
pos = buffer.pos
|
42
44
|
buffer.skip(1)
|
43
45
|
len, = buffer.read(2).unpack('n')
|
44
46
|
type, = buffer.read(1).unpack('C')
|
45
47
|
check_ext!(type)
|
46
48
|
head, = buffer.read(1).unpack('C')
|
47
49
|
data = buffer.read(len-1)
|
48
|
-
parse_ext!(head, data)
|
50
|
+
parse_ext!(head, data, pos)
|
49
51
|
elsif b.start_with?(EXT32)
|
52
|
+
pos = buffer.pos
|
50
53
|
buffer.skip(1)
|
51
54
|
len, = buffer.read(4).unpack('N')
|
52
55
|
type, = buffer.read(1).unpack('C')
|
53
56
|
check_ext!(type)
|
54
57
|
head, = buffer.read(1).unpack('C')
|
55
58
|
data = buffer.read(len-1)
|
56
|
-
parse_ext!(head, data)
|
59
|
+
parse_ext!(head, data, pos)
|
57
60
|
else
|
58
61
|
object = parser.read
|
59
62
|
buffer.seek(parser.unpacker_pos)
|
@@ -88,12 +91,20 @@ module Bones
|
|
88
91
|
end
|
89
92
|
end
|
90
93
|
|
91
|
-
def parse_ext!(head, data)
|
94
|
+
def parse_ext!(head, data, pos)
|
92
95
|
message = Protocol.get_by_ext_head(head)
|
93
96
|
if message
|
94
97
|
message.unpack(data)
|
95
98
|
else
|
96
|
-
|
99
|
+
ext_adapter = Adapter.get_by_ext_head(head)
|
100
|
+
if ext_adapter == adapter
|
101
|
+
buffer.seek(pos)
|
102
|
+
object = parser.read
|
103
|
+
buffer.seek(parser.unpacker_pos)
|
104
|
+
map_from!(object)
|
105
|
+
else
|
106
|
+
raise(Errors::InvalidExtMessage, "bad ext adapter message received of type #{ext_adapter.inspect} (should be #{adapter.inspect})")
|
107
|
+
end
|
97
108
|
end
|
98
109
|
end
|
99
110
|
|
@@ -7,7 +7,11 @@ module Bones
|
|
7
7
|
attr_reader :io
|
8
8
|
|
9
9
|
def initialize(data)
|
10
|
-
@io = StringIO.new(data)
|
10
|
+
@io = data.is_a?(StringIO) ? data : StringIO.new(data)
|
11
|
+
end
|
12
|
+
|
13
|
+
def getbyte
|
14
|
+
io.getbyte
|
11
15
|
end
|
12
16
|
|
13
17
|
def getc
|
@@ -21,7 +25,7 @@ module Bones
|
|
21
25
|
def read(n)
|
22
26
|
i = pos
|
23
27
|
data = io.read(n)
|
24
|
-
if data.bytesize < n
|
28
|
+
if data.nil? || data.bytesize < n
|
25
29
|
seek(i)
|
26
30
|
raise EOFError
|
27
31
|
else
|
@@ -15,7 +15,7 @@ module Bones
|
|
15
15
|
#
|
16
16
|
# @return [ nil ] nil.
|
17
17
|
#
|
18
|
-
# @since
|
18
|
+
# @since 0.0.1
|
19
19
|
def receive_replies(connection); end
|
20
20
|
|
21
21
|
# Serializes the message and all of its fields to a new buffer or to the
|
@@ -28,7 +28,7 @@ module Bones
|
|
28
28
|
#
|
29
29
|
# @return [ String ] The result of serliazing this message
|
30
30
|
#
|
31
|
-
# @since
|
31
|
+
# @since 0.0.1
|
32
32
|
def serialize(buffer, adapter)
|
33
33
|
Adapter.get(adapter).serialize(process, buffer)
|
34
34
|
end
|
@@ -39,7 +39,7 @@ module Bones
|
|
39
39
|
#
|
40
40
|
# @return [ nil ] nil.
|
41
41
|
#
|
42
|
-
# @since
|
42
|
+
# @since 0.0.1
|
43
43
|
def receive_replies(connection); end
|
44
44
|
|
45
45
|
# Serializes the message and all of its fields to a new buffer or to the
|
@@ -52,7 +52,7 @@ module Bones
|
|
52
52
|
#
|
53
53
|
# @return [ String ] The result of serliazing this message
|
54
54
|
#
|
55
|
-
# @since
|
55
|
+
# @since 0.0.1
|
56
56
|
def serialize(buffer = "", adapter = nil)
|
57
57
|
raise NotImplementedError, "This method is generated after calling #finalize on a message class"
|
58
58
|
end
|
@@ -7,14 +7,14 @@ module Bones
|
|
7
7
|
|
8
8
|
# Provides behaviour around getting various read preference implementations.
|
9
9
|
#
|
10
|
-
# @since
|
10
|
+
# @since 0.0.1
|
11
11
|
module ReadPreference
|
12
12
|
extend self
|
13
13
|
|
14
14
|
# Hash lookup for the read preference classes based off the symbols
|
15
15
|
# provided in configuration.
|
16
16
|
#
|
17
|
-
# @since
|
17
|
+
# @since 0.0.1
|
18
18
|
PREFERENCES = {
|
19
19
|
nearest: Nearest
|
20
20
|
}.freeze
|
@@ -34,7 +34,7 @@ module Bones
|
|
34
34
|
#
|
35
35
|
# @return [ Object ] The appropriate read preference.
|
36
36
|
#
|
37
|
-
# @since
|
37
|
+
# @since 0.0.1
|
38
38
|
def get(name, tags = nil)
|
39
39
|
PREFERENCES.fetch(name.to_sym).new(tags)
|
40
40
|
end
|
@@ -5,7 +5,7 @@ module Bones
|
|
5
5
|
|
6
6
|
# Encapsulates behaviour around a nearest read preference.
|
7
7
|
#
|
8
|
-
# @since
|
8
|
+
# @since 0.0.1
|
9
9
|
class Nearest
|
10
10
|
include Selectable
|
11
11
|
|
@@ -16,7 +16,7 @@ module Bones
|
|
16
16
|
#
|
17
17
|
# @return [ Symbol ] :nearest.
|
18
18
|
#
|
19
|
-
# @since
|
19
|
+
# @since 0.0.1
|
20
20
|
def name
|
21
21
|
:nearest
|
22
22
|
end
|
@@ -40,7 +40,7 @@ module Bones
|
|
40
40
|
#
|
41
41
|
# @return [ Object ] The result of the block.
|
42
42
|
#
|
43
|
-
# @since
|
43
|
+
# @since 0.0.1
|
44
44
|
def with_node(cluster, &block)
|
45
45
|
with_retry(cluster) do
|
46
46
|
nearest = cluster.nodes.sort_by(&:latency).first
|