bones-rpc 0.0.1

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 (58) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.ruby-gemset +1 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +8 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +29 -0
  8. data/Rakefile +1 -0
  9. data/bones-rpc.gemspec +29 -0
  10. data/lib/bones-rpc.rb +2 -0
  11. data/lib/bones/rpc.rb +23 -0
  12. data/lib/bones/rpc/adapter.rb +49 -0
  13. data/lib/bones/rpc/adapter/base.rb +41 -0
  14. data/lib/bones/rpc/adapter/erlang.rb +28 -0
  15. data/lib/bones/rpc/adapter/json.rb +23 -0
  16. data/lib/bones/rpc/adapter/msgpack.rb +52 -0
  17. data/lib/bones/rpc/adapter/parser.rb +37 -0
  18. data/lib/bones/rpc/address.rb +167 -0
  19. data/lib/bones/rpc/cluster.rb +266 -0
  20. data/lib/bones/rpc/connection.rb +146 -0
  21. data/lib/bones/rpc/connection/reader.rb +49 -0
  22. data/lib/bones/rpc/connection/socket.rb +4 -0
  23. data/lib/bones/rpc/connection/socket/connectable.rb +196 -0
  24. data/lib/bones/rpc/connection/socket/ssl.rb +35 -0
  25. data/lib/bones/rpc/connection/socket/tcp.rb +28 -0
  26. data/lib/bones/rpc/connection/writer.rb +51 -0
  27. data/lib/bones/rpc/context.rb +48 -0
  28. data/lib/bones/rpc/errors.rb +33 -0
  29. data/lib/bones/rpc/failover.rb +38 -0
  30. data/lib/bones/rpc/failover/disconnect.rb +33 -0
  31. data/lib/bones/rpc/failover/ignore.rb +31 -0
  32. data/lib/bones/rpc/failover/retry.rb +39 -0
  33. data/lib/bones/rpc/future.rb +26 -0
  34. data/lib/bones/rpc/instrumentable.rb +41 -0
  35. data/lib/bones/rpc/instrumentable/log.rb +45 -0
  36. data/lib/bones/rpc/instrumentable/noop.rb +33 -0
  37. data/lib/bones/rpc/loggable.rb +112 -0
  38. data/lib/bones/rpc/node.rb +317 -0
  39. data/lib/bones/rpc/node/registry.rb +32 -0
  40. data/lib/bones/rpc/parser.rb +114 -0
  41. data/lib/bones/rpc/parser/buffer.rb +80 -0
  42. data/lib/bones/rpc/protocol.rb +106 -0
  43. data/lib/bones/rpc/protocol/acknowledge.rb +82 -0
  44. data/lib/bones/rpc/protocol/adapter_helper.rb +164 -0
  45. data/lib/bones/rpc/protocol/binary_helper.rb +431 -0
  46. data/lib/bones/rpc/protocol/ext_message.rb +86 -0
  47. data/lib/bones/rpc/protocol/notify.rb +38 -0
  48. data/lib/bones/rpc/protocol/request.rb +45 -0
  49. data/lib/bones/rpc/protocol/response.rb +58 -0
  50. data/lib/bones/rpc/protocol/synchronize.rb +70 -0
  51. data/lib/bones/rpc/read_preference.rb +43 -0
  52. data/lib/bones/rpc/read_preference/nearest.rb +57 -0
  53. data/lib/bones/rpc/read_preference/selectable.rb +81 -0
  54. data/lib/bones/rpc/readable.rb +57 -0
  55. data/lib/bones/rpc/session.rb +195 -0
  56. data/lib/bones/rpc/uri.rb +222 -0
  57. data/lib/bones/rpc/version.rb +6 -0
  58. metadata +198 -0
@@ -0,0 +1,38 @@
1
+ # encoding: utf-8
2
+ module Bones
3
+ module RPC
4
+ module Protocol
5
+ class Notify
6
+ include AdapterHelper
7
+
8
+ integer :op_code
9
+ binary :method
10
+ list :params
11
+
12
+ finalize
13
+
14
+ def initialize(method, params)
15
+ @method = method
16
+ @params = params
17
+ end
18
+
19
+ undef op_code
20
+
21
+ def op_code
22
+ 2
23
+ end
24
+
25
+ def log_inspect
26
+ type = "NOTIFY"
27
+ fields = []
28
+ fields << ["%-12s", type]
29
+ fields << ["method=%s", method]
30
+ fields << ["params=%s", params]
31
+ f, v = fields.transpose
32
+ f.join(" ") % v
33
+ end
34
+
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,45 @@
1
+ # encoding: utf-8
2
+ module Bones
3
+ module RPC
4
+ module Protocol
5
+ class Request
6
+ include AdapterHelper
7
+
8
+ integer :op_code
9
+ integer :id
10
+ binary :method
11
+ list :params
12
+
13
+ finalize
14
+
15
+ def initialize(id, method, params)
16
+ @id = id
17
+ @method = method
18
+ @params = params
19
+ end
20
+
21
+ undef op_code
22
+
23
+ def op_code
24
+ 0
25
+ end
26
+
27
+ def log_inspect
28
+ type = "REQUEST"
29
+ fields = []
30
+ fields << ["%-12s", type]
31
+ fields << ["id=%s", id]
32
+ fields << ["method=%s", method]
33
+ fields << ["params=%s", params]
34
+ f, v = fields.transpose
35
+ f.join(" ") % v
36
+ end
37
+
38
+ def attach(node, future)
39
+ node.attach(:request, id, future)
40
+ end
41
+
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,58 @@
1
+ # encoding: utf-8
2
+ module Bones
3
+ module RPC
4
+ module Protocol
5
+ class Response
6
+ include AdapterHelper
7
+
8
+ integer :op_code
9
+ integer :id
10
+ any :error
11
+ any :result
12
+
13
+ finalize
14
+
15
+ def initialize(id, error, result)
16
+ @id = id
17
+ @error = error
18
+ @result = result
19
+ end
20
+
21
+ undef op_code
22
+
23
+ def op_code
24
+ @op_code ||= 1
25
+ end
26
+
27
+ def log_inspect
28
+ type = "RESPONSE"
29
+ fields = []
30
+ fields << ["%-12s", type]
31
+ fields << ["id=%s", id]
32
+ fields << ["error=%s", error]
33
+ fields << ["result=%s", result]
34
+ f, v = fields.transpose
35
+ f.join(" ") % v
36
+ end
37
+
38
+ def self.map_from(object)
39
+ message = allocate
40
+ message.op_code = object[0]
41
+ message.id = object[1]
42
+ message.error = object[2]
43
+ message.result = object[3]
44
+ message
45
+ end
46
+
47
+ def get(node)
48
+ node.detach(:request, id)
49
+ end
50
+
51
+ def signal(future)
52
+ future.signal(FutureValue.new(self))
53
+ end
54
+
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,70 @@
1
+ # encoding: utf-8
2
+ module Bones
3
+ module RPC
4
+ module Protocol
5
+ class Synchronize < ExtMessage
6
+
7
+ uint32 :id
8
+ binary :adapter
9
+
10
+ finalize
11
+
12
+ def initialize(id, adapter)
13
+ self.id = id
14
+ self.adapter = adapter
15
+ end
16
+
17
+ undef ext_head
18
+ undef :adapter=
19
+ undef serialize_adapter
20
+
21
+ def ext_head
22
+ 0
23
+ end
24
+
25
+ def adapter=(adapter)
26
+ @adapter = Adapter.get(adapter)
27
+ end
28
+
29
+ def deserialize_adapter(buffer)
30
+ self.adapter = buffer.read(ext_length - 5)
31
+ end
32
+
33
+ def serialize_adapter(buffer)
34
+ buffer << adapter.adapter_name.to_s
35
+ end
36
+
37
+ def log_inspect
38
+ type = "SYNCHRONIZE"
39
+ fields = []
40
+ fields << ["%-12s", type]
41
+ fields << ["id=%s", id]
42
+ fields << ["adapter=%s", adapter]
43
+ f, v = fields.transpose
44
+ f.join(" ") % v
45
+ end
46
+
47
+ def self.deserialize(buffer, adapter = nil)
48
+ message = super
49
+ message.deserialize_id(buffer)
50
+ message.deserialize_adapter(buffer)
51
+ message
52
+ end
53
+
54
+ def self.unpack(data)
55
+ buffer = StringIO.new(data)
56
+ id, = buffer.read(4).unpack('N')
57
+ adapter = buffer.read
58
+ new(id, adapter)
59
+ end
60
+
61
+ def attach(node, future)
62
+ node.attach(:synack, id, future)
63
+ end
64
+
65
+ Protocol.register_ext_head self, 0
66
+
67
+ end
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,43 @@
1
+ # encoding: utf-8
2
+ require 'bones/rpc/read_preference/selectable'
3
+ require 'bones/rpc/read_preference/nearest'
4
+
5
+ module Bones
6
+ module RPC
7
+
8
+ # Provides behaviour around getting various read preference implementations.
9
+ #
10
+ # @since 2.0.0
11
+ module ReadPreference
12
+ extend self
13
+
14
+ # Hash lookup for the read preference classes based off the symbols
15
+ # provided in configuration.
16
+ #
17
+ # @since 2.0.0
18
+ PREFERENCES = {
19
+ nearest: Nearest
20
+ }.freeze
21
+
22
+ # Get a read preference for the provided name. Valid names are:
23
+ # - :nearest
24
+ # - :primary
25
+ # - :primary_preferred
26
+ # - :secondary
27
+ # - :secondary_preferred
28
+ #
29
+ # @example Get the primary read preference.
30
+ # Bones::RPC::ReadPreference.get(:primary)
31
+ #
32
+ # @param [ Symbol ] name The name of the preference.
33
+ # @param [ Array<Hash> ] tags The tag sets to match the node on.
34
+ #
35
+ # @return [ Object ] The appropriate read preference.
36
+ #
37
+ # @since 2.0.0
38
+ def get(name, tags = nil)
39
+ PREFERENCES.fetch(name.to_sym).new(tags)
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,57 @@
1
+ # encoding: utf-8
2
+ module Bones
3
+ module RPC
4
+ module ReadPreference
5
+
6
+ # Encapsulates behaviour around a nearest read preference.
7
+ #
8
+ # @since 2.0.0
9
+ class Nearest
10
+ include Selectable
11
+
12
+ # Get the name for the read preference on the server side.
13
+ #
14
+ # @example Get the name of the read preference.
15
+ # nearest.name
16
+ #
17
+ # @return [ Symbol ] :nearest.
18
+ #
19
+ # @since 2.0.0
20
+ def name
21
+ :nearest
22
+ end
23
+
24
+ # Execute the provided block on the node with the lowest latency,
25
+ # allowing either primary or secondary.
26
+ #
27
+ # @example Read from the nearest node in the cluster.
28
+ # preference.with_node(cluster) do |node|
29
+ # node.command(ismaster: 1)
30
+ # end
31
+ #
32
+ # @note If tag sets are provided then selection will need to
33
+ # match the provided tags.
34
+ #
35
+ # @param [ Cluster ] cluster The cluster of nodes to select from.
36
+ # @param [ Proc ] block The block to execute on the node.
37
+ #
38
+ # @raise [ Errors::ConnectionFailure ] If no node was available in the
39
+ # cluster.
40
+ #
41
+ # @return [ Object ] The result of the block.
42
+ #
43
+ # @since 2.0.0
44
+ def with_node(cluster, &block)
45
+ with_retry(cluster) do
46
+ nearest = cluster.nodes.sort_by(&:latency).first
47
+ if nearest
48
+ block.call(nearest)
49
+ else
50
+ raise Errors::ConnectionFailure, "No nodes available to select in the cluster"
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,81 @@
1
+ # encoding: utf-8
2
+ module Bones
3
+ module RPC
4
+ module ReadPreference
5
+
6
+ # Provides the shared behaviour for read preferences that can filter by a
7
+ # tag set or add query options.
8
+ #
9
+ # @since 2.0.0
10
+ module Selectable
11
+
12
+ # @!attribute tags
13
+ # @return [ Array<Hash> ] The tag sets.
14
+ attr_reader :tags
15
+
16
+ # Instantiate the new taggable read preference.
17
+ #
18
+ # @example Instantiate the taggable.
19
+ # Bones::RPC::ReadPreference::Secondary.new({ east_coast: 1 })
20
+ #
21
+ # @param [ Array<Hash> ] tags The tag sets.
22
+ #
23
+ # @since 2.0.0
24
+ def initialize(tags = nil)
25
+ @tags = tags
26
+ end
27
+
28
+ # Get the provided options as query options for this read preference.
29
+ #
30
+ # @example Get the query options.
31
+ # preference.query_options({})
32
+ #
33
+ # @param [ Hash ] options The existing options for the query.
34
+ #
35
+ # @return [ Hash ] The options plus additional query options.
36
+ #
37
+ # @since 2.0.0
38
+ def query_options(options)
39
+ options[:flags] ||= []
40
+ options[:flags] |= [ :slave_ok ]
41
+ options
42
+ end
43
+
44
+ private
45
+
46
+ # Execute the provided block on the cluster and retry if the execution
47
+ # fails.
48
+ #
49
+ # @api private
50
+ #
51
+ # @example Execute with retry.
52
+ # preference.with_retry(cluster) do
53
+ # cluster.with_primary do |node|
54
+ # node.refresh
55
+ # end
56
+ # end
57
+ #
58
+ # @param [ Cluster ] cluster The cluster.
59
+ # @param [ Integer ] retries The number of times to retry.
60
+ #
61
+ # @return [ Object ] The result of the block.
62
+ #
63
+ # @since 2.0.0
64
+ def with_retry(cluster, retries = cluster.max_retries, &block)
65
+ begin
66
+ block.call
67
+ rescue Errors::ConnectionFailure => e
68
+ if retries > 0
69
+ Loggable.warn(" BONES-RPC:", "Retrying connection attempt #{retries} more time(s).", "n/a")
70
+ sleep(cluster.retry_interval)
71
+ cluster.refresh
72
+ with_retry(cluster, retries - 1, &block)
73
+ else
74
+ raise e
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,57 @@
1
+ # encoding: utf-8
2
+ module Bones
3
+ module RPC
4
+
5
+ # Provides behaviour around readable objects.
6
+ #
7
+ # @since 2.0.0
8
+ module Readable
9
+
10
+ private
11
+
12
+ # Convenience method for getting the cluster from the session.
13
+ #
14
+ # @api private
15
+ #
16
+ # @example Get the cluster from the session.
17
+ # database.cluster
18
+ #
19
+ # @return [ Cluster ] The cluster.
20
+ #
21
+ # @since 2.0.0
22
+ def cluster
23
+ session.cluster
24
+ end
25
+
26
+ # Convenience method for getting the read preference from the session.
27
+ #
28
+ # @api private
29
+ #
30
+ # @example Get the read preference.
31
+ # database.read_preference
32
+ #
33
+ # @return [ Object ] The session's read preference.
34
+ #
35
+ # @since 2.0.0
36
+ def read_preference
37
+ session.read_preference
38
+ end
39
+
40
+ # Get the query options from the read preference.
41
+ #
42
+ # @api private
43
+ #
44
+ # @example Get the query options.
45
+ # database.query_options
46
+ #
47
+ # @param [ Hash ] options The existing options on the query.
48
+ #
49
+ # @return [ Hash ] The new query options.
50
+ #
51
+ # @since 2.0.0
52
+ def query_options(options = {})
53
+ read_preference.query_options(options)
54
+ end
55
+ end
56
+ end
57
+ end