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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-gemset +1 -1
  3. data/.ruby-version +1 -1
  4. data/bones-rpc.gemspec +1 -4
  5. data/lib/bones/rpc.rb +1 -1
  6. data/lib/bones/rpc/adapter.rb +44 -4
  7. data/lib/bones/rpc/adapter/json.rb +66 -0
  8. data/lib/bones/rpc/address.rb +6 -4
  9. data/lib/bones/rpc/backend.rb +31 -0
  10. data/lib/bones/rpc/backend/base.rb +30 -0
  11. data/lib/bones/rpc/backend/synchronous.rb +29 -0
  12. data/lib/bones/rpc/cluster.rb +18 -18
  13. data/lib/bones/rpc/connection.rb +19 -15
  14. data/lib/bones/rpc/connection/socket.rb +0 -2
  15. data/lib/bones/rpc/connection/socket/connectable.rb +15 -11
  16. data/lib/bones/rpc/context.rb +2 -2
  17. data/lib/bones/rpc/dns_resolver.rb +85 -0
  18. data/lib/bones/rpc/errors.rb +3 -0
  19. data/lib/bones/rpc/failover.rb +3 -3
  20. data/lib/bones/rpc/failover/disconnect.rb +2 -2
  21. data/lib/bones/rpc/failover/ignore.rb +2 -2
  22. data/lib/bones/rpc/failover/retry.rb +2 -2
  23. data/lib/bones/rpc/instrumentable.rb +3 -3
  24. data/lib/bones/rpc/instrumentable/log.rb +2 -2
  25. data/lib/bones/rpc/instrumentable/noop.rb +2 -2
  26. data/lib/bones/rpc/loggable.rb +8 -8
  27. data/lib/bones/rpc/node.rb +47 -37
  28. data/lib/bones/rpc/node/registry.rb +4 -0
  29. data/lib/bones/rpc/parser.rb +16 -5
  30. data/lib/bones/rpc/parser/buffer.rb +6 -2
  31. data/lib/bones/rpc/protocol/adapter_helper.rb +2 -2
  32. data/lib/bones/rpc/protocol/binary_helper.rb +2 -2
  33. data/lib/bones/rpc/read_preference.rb +3 -3
  34. data/lib/bones/rpc/read_preference/nearest.rb +3 -3
  35. data/lib/bones/rpc/read_preference/selectable.rb +4 -4
  36. data/lib/bones/rpc/readable.rb +4 -4
  37. data/lib/bones/rpc/session.rb +25 -16
  38. data/lib/bones/rpc/synchronous.rb +2 -0
  39. data/lib/bones/rpc/synchronous/connection.rb +36 -0
  40. data/lib/bones/rpc/synchronous/connection/reader.rb +59 -0
  41. data/lib/bones/rpc/synchronous/connection/socket.rb +4 -0
  42. data/lib/bones/rpc/synchronous/connection/socket/ssl.rb +57 -0
  43. data/lib/bones/rpc/synchronous/connection/socket/tcp.rb +30 -0
  44. data/lib/bones/rpc/synchronous/connection/writer.rb +86 -0
  45. data/lib/bones/rpc/synchronous/future.rb +91 -0
  46. data/lib/bones/rpc/synchronous/node.rb +45 -0
  47. data/lib/bones/rpc/uri.rb +20 -20
  48. data/lib/bones/rpc/version.rb +1 -1
  49. metadata +16 -52
  50. data/lib/bones/rpc/adapter/erlang.rb +0 -28
  51. data/lib/bones/rpc/adapter/msgpack.rb +0 -52
  52. data/lib/bones/rpc/connection/reader.rb +0 -49
  53. data/lib/bones/rpc/connection/socket/ssl.rb +0 -35
  54. data/lib/bones/rpc/connection/socket/tcp.rb +0 -28
  55. data/lib/bones/rpc/connection/writer.rb +0 -51
  56. data/lib/bones/rpc/future.rb +0 -26
@@ -4,7 +4,7 @@ module Bones
4
4
 
5
5
  # Contains behaviour for logging.
6
6
  #
7
- # @since 1.0.0
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 2.0.0
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 2.0.0
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 2.0.0
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 1.0.0
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 1.0.0
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 1.0.0
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 1.0.0
106
+ # @since 0.0.1
107
107
  def logger=(logger)
108
108
  @logger = logger
109
109
  end
@@ -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 1.0.0
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 1.0.0
38
+ # @since 0.0.1
41
39
  def ==(other)
42
40
  return false unless other.is_a?(Node)
43
- id == other.id
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] || :msgpack)
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 2.0.0
66
+ # @since 0.0.1
69
67
  def connect
70
68
  start = Time.now
71
- @connection.connect
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 2.0.0
82
+ # @since 0.0.1
85
83
  def connected?
86
- @connection.alive?
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 1.2.0
106
+ # @since 0.0.1
101
107
  def disconnect
102
- @connection.disconnect
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 1.0.0
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 2.0.0
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 1.0.0
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 = Connection.new(current_actor)
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(self)
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 1.0.0
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 1.0.0
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 1.0.0
229
+ # @since 0.0.1
224
230
  def refresh
225
- if address.resolve(self)
231
+ if address.resolve(current_actor)
226
232
  begin
227
233
  @refreshed_at = Time.now
228
- if synchronize.value(timeout)
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.timeout
248
+ # node.refresh_timeout
251
249
  #
252
250
  # @return [ Integer ] The configured timeout or the default of 5.
253
251
  #
254
- # @since 1.0.0
255
- def timeout
256
- @timeout ||= (options[:timeout] || 5)
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 2.0.0
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
- @connection.write([[message, future]])
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, Future.new)
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|
@@ -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
- map_from!(Adapter.get_by_ext_head(head).unpack(data))
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 1.0.0
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 1.0.0
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 1.0.0
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 1.0.0
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 2.0.0
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 2.0.0
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 2.0.0
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 2.0.0
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 2.0.0
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 2.0.0
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