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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/bones-rpc.gemspec +29 -0
- data/lib/bones-rpc.rb +2 -0
- data/lib/bones/rpc.rb +23 -0
- data/lib/bones/rpc/adapter.rb +49 -0
- data/lib/bones/rpc/adapter/base.rb +41 -0
- data/lib/bones/rpc/adapter/erlang.rb +28 -0
- data/lib/bones/rpc/adapter/json.rb +23 -0
- data/lib/bones/rpc/adapter/msgpack.rb +52 -0
- data/lib/bones/rpc/adapter/parser.rb +37 -0
- data/lib/bones/rpc/address.rb +167 -0
- data/lib/bones/rpc/cluster.rb +266 -0
- data/lib/bones/rpc/connection.rb +146 -0
- data/lib/bones/rpc/connection/reader.rb +49 -0
- data/lib/bones/rpc/connection/socket.rb +4 -0
- data/lib/bones/rpc/connection/socket/connectable.rb +196 -0
- data/lib/bones/rpc/connection/socket/ssl.rb +35 -0
- data/lib/bones/rpc/connection/socket/tcp.rb +28 -0
- data/lib/bones/rpc/connection/writer.rb +51 -0
- data/lib/bones/rpc/context.rb +48 -0
- data/lib/bones/rpc/errors.rb +33 -0
- data/lib/bones/rpc/failover.rb +38 -0
- data/lib/bones/rpc/failover/disconnect.rb +33 -0
- data/lib/bones/rpc/failover/ignore.rb +31 -0
- data/lib/bones/rpc/failover/retry.rb +39 -0
- data/lib/bones/rpc/future.rb +26 -0
- data/lib/bones/rpc/instrumentable.rb +41 -0
- data/lib/bones/rpc/instrumentable/log.rb +45 -0
- data/lib/bones/rpc/instrumentable/noop.rb +33 -0
- data/lib/bones/rpc/loggable.rb +112 -0
- data/lib/bones/rpc/node.rb +317 -0
- data/lib/bones/rpc/node/registry.rb +32 -0
- data/lib/bones/rpc/parser.rb +114 -0
- data/lib/bones/rpc/parser/buffer.rb +80 -0
- data/lib/bones/rpc/protocol.rb +106 -0
- data/lib/bones/rpc/protocol/acknowledge.rb +82 -0
- data/lib/bones/rpc/protocol/adapter_helper.rb +164 -0
- data/lib/bones/rpc/protocol/binary_helper.rb +431 -0
- data/lib/bones/rpc/protocol/ext_message.rb +86 -0
- data/lib/bones/rpc/protocol/notify.rb +38 -0
- data/lib/bones/rpc/protocol/request.rb +45 -0
- data/lib/bones/rpc/protocol/response.rb +58 -0
- data/lib/bones/rpc/protocol/synchronize.rb +70 -0
- data/lib/bones/rpc/read_preference.rb +43 -0
- data/lib/bones/rpc/read_preference/nearest.rb +57 -0
- data/lib/bones/rpc/read_preference/selectable.rb +81 -0
- data/lib/bones/rpc/readable.rb +57 -0
- data/lib/bones/rpc/session.rb +195 -0
- data/lib/bones/rpc/uri.rb +222 -0
- data/lib/bones/rpc/version.rb +6 -0
- metadata +198 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Bones
|
3
|
+
module RPC
|
4
|
+
module Failover
|
5
|
+
|
6
|
+
# Ignore is for the case when we get exceptions we deem are proper user
|
7
|
+
# or datbase errors and should be re-raised.
|
8
|
+
#
|
9
|
+
# @since 2.0.0
|
10
|
+
module Ignore
|
11
|
+
extend self
|
12
|
+
|
13
|
+
# Executes the failover strategy. In the case of ignore, we just re-raise
|
14
|
+
# the exception that was thrown previously.
|
15
|
+
#
|
16
|
+
# @example Execute the ignore strategy.
|
17
|
+
# Bones::RPC::Failover::Ignore.execute(exception, node)
|
18
|
+
#
|
19
|
+
# @param [ Exception ] exception The raised exception.
|
20
|
+
# @param [ Node ] node The node the exception got raised on.
|
21
|
+
#
|
22
|
+
# @raise [ Exception ] The exception that was previously thrown.
|
23
|
+
#
|
24
|
+
# @since 2.0.0
|
25
|
+
def execute(exception, node)
|
26
|
+
raise(exception)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Bones
|
3
|
+
module RPC
|
4
|
+
module Failover
|
5
|
+
|
6
|
+
# Retry is for the case when we get exceptions around the connection, and
|
7
|
+
# want to make another attempt to try and resolve the issue.
|
8
|
+
#
|
9
|
+
# @since 2.0.0
|
10
|
+
module Retry
|
11
|
+
extend self
|
12
|
+
|
13
|
+
# Executes the failover strategy. In the case of retyr, we disconnect and
|
14
|
+
# reconnect, then try the operation one more time.
|
15
|
+
#
|
16
|
+
# @example Execute the retry strategy.
|
17
|
+
# Bones::RPC::Failover::Retry.execute(exception, node)
|
18
|
+
#
|
19
|
+
# @param [ Exception ] exception The raised exception.
|
20
|
+
# @param [ Node ] node The node the exception got raised on.
|
21
|
+
#
|
22
|
+
# @raise [ Errors::ConnectionFailure ] If the retry fails.
|
23
|
+
#
|
24
|
+
# @return [ Object ] The result of the block yield.
|
25
|
+
#
|
26
|
+
# @since 2.0.0
|
27
|
+
def execute(exception, node)
|
28
|
+
node.disconnect
|
29
|
+
begin
|
30
|
+
yield if block_given?
|
31
|
+
rescue Exception => e
|
32
|
+
node.down
|
33
|
+
raise(e)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Bones
|
3
|
+
module RPC
|
4
|
+
class Future < ::Celluloid::Future
|
5
|
+
|
6
|
+
def initialize(*args, &block)
|
7
|
+
@start = Time.now
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def signal(*args, &block)
|
12
|
+
@stop = Time.now
|
13
|
+
super
|
14
|
+
end
|
15
|
+
|
16
|
+
def runtime
|
17
|
+
if @stop
|
18
|
+
@stop - @start
|
19
|
+
else
|
20
|
+
Time.now - @start
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'bones/rpc/instrumentable/log'
|
3
|
+
require 'bones/rpc/instrumentable/noop'
|
4
|
+
|
5
|
+
module Bones
|
6
|
+
module RPC
|
7
|
+
module Instrumentable
|
8
|
+
|
9
|
+
# The name of the topic of operations for Bones::RPC.
|
10
|
+
#
|
11
|
+
# @since 2.0.0
|
12
|
+
TOPIC = "bones-rpc.operations"
|
13
|
+
|
14
|
+
# Topic for warning instrumentation.
|
15
|
+
#
|
16
|
+
# @since 2.0.0
|
17
|
+
WARN = "bones-rpc.warn"
|
18
|
+
|
19
|
+
# @!attribute instrumenter
|
20
|
+
# @return [ Object ] The instrumenter
|
21
|
+
attr_reader :instrumenter
|
22
|
+
|
23
|
+
# Instrument and execute the provided block.
|
24
|
+
#
|
25
|
+
# @example Instrument and execute.
|
26
|
+
# instrument("bones-rpc.noop") do
|
27
|
+
# node.connect
|
28
|
+
# end
|
29
|
+
#
|
30
|
+
# @param [ String ] name The name of the operation.
|
31
|
+
# @param [ Hash ] payload The payload.
|
32
|
+
#
|
33
|
+
# @return [ Object ] The result of the yield.
|
34
|
+
#
|
35
|
+
# @since 2.0.0
|
36
|
+
def instrument(name, payload = {}, &block)
|
37
|
+
instrumenter.instrument(name, payload, &block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Bones
|
3
|
+
module RPC
|
4
|
+
module Instrumentable
|
5
|
+
|
6
|
+
# Provides logging instrumentation for compatibility with active support
|
7
|
+
# notifications.
|
8
|
+
#
|
9
|
+
# @since 2.0.0
|
10
|
+
class Log
|
11
|
+
|
12
|
+
class << self
|
13
|
+
|
14
|
+
# Instrument the log payload.
|
15
|
+
#
|
16
|
+
# @example Instrument the log payload.
|
17
|
+
# Log.instrument("bones-rpc.ops", {})
|
18
|
+
#
|
19
|
+
# @param [ String ] name The name of the logging type.
|
20
|
+
# @param [ Hash ] payload The log payload.
|
21
|
+
#
|
22
|
+
# @return [ Object ] The result of the yield.
|
23
|
+
#
|
24
|
+
# @since 2.0.0
|
25
|
+
def instrument(name, payload = {})
|
26
|
+
started = Time.new
|
27
|
+
begin
|
28
|
+
yield if block_given?
|
29
|
+
rescue Exception => e
|
30
|
+
payload[:exception] = [ e.class.name, e.message ]
|
31
|
+
raise e
|
32
|
+
ensure
|
33
|
+
runtime = ("%.4fms" % (1000 * (Time.now.to_f - started.to_f)))
|
34
|
+
if name == TOPIC
|
35
|
+
Bones::RPC::Loggable.log_operations(payload[:prefix], payload[:ops], runtime)
|
36
|
+
else
|
37
|
+
Bones::RPC::Loggable.debug(payload[:prefix], payload.reject { |k,v| k == :prefix }, runtime)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Bones
|
3
|
+
module RPC
|
4
|
+
module Instrumentable
|
5
|
+
|
6
|
+
# Does not instrument anything, just yields.
|
7
|
+
#
|
8
|
+
# @since 2.0.0
|
9
|
+
class Noop
|
10
|
+
|
11
|
+
class << self
|
12
|
+
|
13
|
+
# Do not instrument anything.
|
14
|
+
#
|
15
|
+
# @example Do not instrument.
|
16
|
+
# Noop.instrument("bones-rpc.noop") do
|
17
|
+
# node.connect
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# @param [ String ] name The name of the operation.
|
21
|
+
# @param [ Hash ] payload The payload.
|
22
|
+
#
|
23
|
+
# @return [ Object ] The result of the yield.
|
24
|
+
#
|
25
|
+
# @since 2.0.0
|
26
|
+
def instrument(name, payload = {})
|
27
|
+
yield payload if block_given?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Bones
|
3
|
+
module RPC
|
4
|
+
|
5
|
+
# Contains behaviour for logging.
|
6
|
+
#
|
7
|
+
# @since 1.0.0
|
8
|
+
module Loggable
|
9
|
+
|
10
|
+
# Log the provided operations.
|
11
|
+
#
|
12
|
+
# @example Log the operations.
|
13
|
+
# Loggable.log_operations("BONES-RPC", {}, 30)
|
14
|
+
#
|
15
|
+
# @param [ String ] prefix The prefix for all operations in the log.
|
16
|
+
# @param [ Array ] ops The operations.
|
17
|
+
# @param [ String ] runtime The runtime in formatted ms.
|
18
|
+
#
|
19
|
+
# @since 2.0.0
|
20
|
+
def self.log_operations(prefix, ops, runtime)
|
21
|
+
indent = " "*prefix.length
|
22
|
+
if ops.length == 1
|
23
|
+
Bones::RPC.logger.debug([ prefix, ops.first.log_inspect, "runtime: #{runtime}" ].join(' '))
|
24
|
+
else
|
25
|
+
first, *middle, last = ops
|
26
|
+
Bones::RPC.logger.debug([ prefix, first.log_inspect ].join(' '))
|
27
|
+
middle.each { |m| Bones::RPC.logger.debug([ indent, m.log_inspect ].join(' ')) }
|
28
|
+
Bones::RPC.logger.debug([ indent, last.log_inspect, "runtime: #{runtime}" ].join(' '))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# Log the payload to debug.
|
33
|
+
#
|
34
|
+
# @example Log to debug.
|
35
|
+
# Loggable.debug("BONES-RPC", payload "30.012ms")
|
36
|
+
#
|
37
|
+
# @param [ String ] prefix The log prefix.
|
38
|
+
# @param [ String ] payload The log operations.
|
39
|
+
# @param [ String ] runtime The runtime in formatted ms.
|
40
|
+
#
|
41
|
+
# @since 2.0.0
|
42
|
+
def self.debug(prefix, payload, runtime)
|
43
|
+
Bones::RPC.logger.debug([ prefix, payload, "runtime: #{runtime}" ].join(' '))
|
44
|
+
end
|
45
|
+
|
46
|
+
# Log the payload to warn.
|
47
|
+
#
|
48
|
+
# @example Log to warn.
|
49
|
+
# Loggable.warn("BONES-RPC", payload "30.012ms")
|
50
|
+
#
|
51
|
+
# @param [ String ] prefix The log prefix.
|
52
|
+
# @param [ String ] payload The log operations.
|
53
|
+
# @param [ String ] runtime The runtime in formatted ms.
|
54
|
+
#
|
55
|
+
# @since 2.0.0
|
56
|
+
def self.warn(prefix, payload, runtime)
|
57
|
+
Bones::RPC.logger.warn([ prefix, payload, "runtime: #{runtime}" ].join(' '))
|
58
|
+
end
|
59
|
+
|
60
|
+
# Get the logger.
|
61
|
+
#
|
62
|
+
# @example Get the logger.
|
63
|
+
# Loggable.logger
|
64
|
+
#
|
65
|
+
# @return [ Logger ] The logger.
|
66
|
+
#
|
67
|
+
# @since 1.0.0
|
68
|
+
def logger
|
69
|
+
return @logger if defined?(@logger)
|
70
|
+
@logger = rails_logger || default_logger
|
71
|
+
end
|
72
|
+
|
73
|
+
# Get the rails logger.
|
74
|
+
#
|
75
|
+
# @example Get the rails logger.
|
76
|
+
# Loggable.rails_logger
|
77
|
+
#
|
78
|
+
# @return [ Logger ] The Rails logger.
|
79
|
+
#
|
80
|
+
# @since 1.0.0
|
81
|
+
def rails_logger
|
82
|
+
defined?(Rails) && Rails.respond_to?(:logger) && Rails.logger
|
83
|
+
end
|
84
|
+
|
85
|
+
# Get the default logger.
|
86
|
+
#
|
87
|
+
# @example Get the default logger.
|
88
|
+
# Loggable.default_logger
|
89
|
+
#
|
90
|
+
# @return [ Logger ] The default logger.
|
91
|
+
#
|
92
|
+
# @since 1.0.0
|
93
|
+
def default_logger
|
94
|
+
logger = Logger.new(STDOUT)
|
95
|
+
logger.level = Logger::INFO
|
96
|
+
logger
|
97
|
+
end
|
98
|
+
|
99
|
+
# Set the logger.
|
100
|
+
#
|
101
|
+
# @example Set the logger.
|
102
|
+
# Loggable.logger = logger
|
103
|
+
#
|
104
|
+
# @return [ Logger ] The logger.
|
105
|
+
#
|
106
|
+
# @since 1.0.0
|
107
|
+
def logger=(logger)
|
108
|
+
@logger = logger
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,317 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'bones/rpc/address'
|
3
|
+
require 'bones/rpc/connection'
|
4
|
+
require 'bones/rpc/failover'
|
5
|
+
require 'bones/rpc/future'
|
6
|
+
require 'bones/rpc/instrumentable'
|
7
|
+
require 'bones/rpc/node/registry'
|
8
|
+
|
9
|
+
module Bones
|
10
|
+
module RPC
|
11
|
+
|
12
|
+
# Represents a client to a node in a server cluster.
|
13
|
+
#
|
14
|
+
# @since 1.0.0
|
15
|
+
class Node
|
16
|
+
include Celluloid
|
17
|
+
include Instrumentable
|
18
|
+
|
19
|
+
# @!attribute address
|
20
|
+
# @return [ Address ] The address.
|
21
|
+
# @!attribute down_at
|
22
|
+
# @return [ Time ] The time the node was marked as down.
|
23
|
+
# @!attribute latency
|
24
|
+
# @return [ Integer ] The latency in milliseconds.
|
25
|
+
# @!attribute options
|
26
|
+
# @return [ Hash ] The node options.
|
27
|
+
# @!attribute refreshed_at
|
28
|
+
# @return [ Time ] The last time the node did a refresh.
|
29
|
+
attr_reader :cluster, :address, :down_at, :latency, :refreshed_at
|
30
|
+
|
31
|
+
# Is this node equal to another?
|
32
|
+
#
|
33
|
+
# @example Is the node equal to another.
|
34
|
+
# node == other
|
35
|
+
#
|
36
|
+
# @param [ Node ] other The other node.
|
37
|
+
#
|
38
|
+
# @return [ true, false ] If the addresses are equal.
|
39
|
+
#
|
40
|
+
# @since 1.0.0
|
41
|
+
def ==(other)
|
42
|
+
return false unless other.is_a?(Node)
|
43
|
+
id == other.id
|
44
|
+
end
|
45
|
+
alias :eql? :==
|
46
|
+
|
47
|
+
def adapter
|
48
|
+
@adapter ||= Adapter.get(options[:adapter] || :msgpack)
|
49
|
+
end
|
50
|
+
|
51
|
+
def attach(channel, id, future)
|
52
|
+
@registry.set(channel, id, future)
|
53
|
+
end
|
54
|
+
|
55
|
+
def cleanup_socket(socket)
|
56
|
+
@registry.flush
|
57
|
+
end
|
58
|
+
|
59
|
+
# Connect the node on the underlying connection.
|
60
|
+
#
|
61
|
+
# @example Connect the node.
|
62
|
+
# node.connect
|
63
|
+
#
|
64
|
+
# @raise [ Errors::ConnectionFailure ] If connection failed.
|
65
|
+
#
|
66
|
+
# @return [ true ] If the connection suceeded.
|
67
|
+
#
|
68
|
+
# @since 2.0.0
|
69
|
+
def connect
|
70
|
+
start = Time.now
|
71
|
+
@connection.connect
|
72
|
+
@latency = Time.now - start
|
73
|
+
@down_at = nil
|
74
|
+
true
|
75
|
+
end
|
76
|
+
|
77
|
+
# Is the node currently connected?
|
78
|
+
#
|
79
|
+
# @example Is the node connected?
|
80
|
+
# node.connected?
|
81
|
+
#
|
82
|
+
# @return [ true, false ] If the node is connected or not.
|
83
|
+
#
|
84
|
+
# @since 2.0.0
|
85
|
+
def connected?
|
86
|
+
@connection.alive?
|
87
|
+
end
|
88
|
+
|
89
|
+
def detach(channel, id)
|
90
|
+
@registry.get(channel, id)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Force the node to disconnect from the server.
|
94
|
+
#
|
95
|
+
# @example Disconnect the node.
|
96
|
+
# node.disconnect
|
97
|
+
#
|
98
|
+
# @return [ true ] If the disconnection succeeded.
|
99
|
+
#
|
100
|
+
# @since 1.2.0
|
101
|
+
def disconnect
|
102
|
+
@connection.disconnect
|
103
|
+
true
|
104
|
+
end
|
105
|
+
|
106
|
+
# Is the node down?
|
107
|
+
#
|
108
|
+
# @example Is the node down?
|
109
|
+
# node.down?
|
110
|
+
#
|
111
|
+
# @return [ Time, nil ] The time the node went down, or nil if up.
|
112
|
+
#
|
113
|
+
# @since 1.0.0
|
114
|
+
def down?
|
115
|
+
!!@down_at
|
116
|
+
end
|
117
|
+
|
118
|
+
# Mark the node as down.
|
119
|
+
#
|
120
|
+
# @example Mark the node as down.
|
121
|
+
# node.down
|
122
|
+
#
|
123
|
+
# @return [ nil ] Nothing.
|
124
|
+
#
|
125
|
+
# @since 2.0.0
|
126
|
+
def down
|
127
|
+
@down_at = Time.new
|
128
|
+
@latency = nil
|
129
|
+
disconnect if connected?
|
130
|
+
end
|
131
|
+
|
132
|
+
# Yields the block if a connection can be established, retrying when a
|
133
|
+
# connection error is raised.
|
134
|
+
#
|
135
|
+
# @example Ensure we are connection.
|
136
|
+
# node.ensure_connected do
|
137
|
+
# #...
|
138
|
+
# end
|
139
|
+
#
|
140
|
+
# @raises [ ConnectionFailure ] When a connection cannot be established.
|
141
|
+
#
|
142
|
+
# @return [ nil ] nil.
|
143
|
+
#
|
144
|
+
# @since 1.0.0
|
145
|
+
def ensure_connected(&block)
|
146
|
+
begin
|
147
|
+
connect unless connected?
|
148
|
+
yield(current_actor)
|
149
|
+
rescue Exception => e
|
150
|
+
Failover.get(e).execute(e, current_actor, &block)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def handle_message(message)
|
155
|
+
logging(message) do
|
156
|
+
if future = message.get(current_actor)
|
157
|
+
message.signal(future)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def initialize(cluster, address)
|
163
|
+
@cluster = cluster
|
164
|
+
@address = address
|
165
|
+
@connection = Connection.new(current_actor)
|
166
|
+
@down_at = nil
|
167
|
+
@refreshed_at = nil
|
168
|
+
@latency = nil
|
169
|
+
@instrumenter = @cluster.options[:instrumenter] || Instrumentable::Log
|
170
|
+
@registry = Node::Registry.new
|
171
|
+
@request_id = 0
|
172
|
+
@synack_id = 0
|
173
|
+
@address.resolve(self)
|
174
|
+
end
|
175
|
+
|
176
|
+
# Get the node as a nice formatted string.
|
177
|
+
#
|
178
|
+
# @example Inspect the node.
|
179
|
+
# node.inspect
|
180
|
+
#
|
181
|
+
# @return [ String ] The string inspection.
|
182
|
+
#
|
183
|
+
# @since 1.0.0
|
184
|
+
def inspect
|
185
|
+
"<#{self.class.name} resolved_address=#{address.resolved.inspect}>"
|
186
|
+
end
|
187
|
+
|
188
|
+
# Does the node need to be refreshed?
|
189
|
+
#
|
190
|
+
# @example Does the node require refreshing?
|
191
|
+
# node.needs_refresh?(time)
|
192
|
+
#
|
193
|
+
# @param [ Time ] time The next referesh time.
|
194
|
+
#
|
195
|
+
# @return [ true, false] Whether the node needs to be refreshed.
|
196
|
+
#
|
197
|
+
# @since 1.0.0
|
198
|
+
def needs_refresh?(time)
|
199
|
+
!refreshed_at || refreshed_at < time
|
200
|
+
end
|
201
|
+
|
202
|
+
def notify(method, params)
|
203
|
+
without_future(Protocol::Notify.new(method, params))
|
204
|
+
end
|
205
|
+
|
206
|
+
def options
|
207
|
+
cluster.options
|
208
|
+
end
|
209
|
+
|
210
|
+
# Refresh information about the node, such as it's status in the replica
|
211
|
+
# set and it's known peers.
|
212
|
+
#
|
213
|
+
# @example Refresh the node.
|
214
|
+
# node.refresh
|
215
|
+
#
|
216
|
+
# @raise [ ConnectionFailure ] If the node cannot be reached.
|
217
|
+
#
|
218
|
+
# @raise [ ReplicaSetReconfigured ] If the node is no longer a primary node and
|
219
|
+
# refresh was called within an +#ensure_primary+ block.
|
220
|
+
#
|
221
|
+
# @return [ nil ] nil.
|
222
|
+
#
|
223
|
+
# @since 1.0.0
|
224
|
+
def refresh
|
225
|
+
if address.resolve(self)
|
226
|
+
begin
|
227
|
+
@refreshed_at = Time.now
|
228
|
+
if synchronize.value(timeout)
|
229
|
+
cluster.handle_refresh(current_actor)
|
230
|
+
else
|
231
|
+
down
|
232
|
+
end
|
233
|
+
rescue Timeout::Error
|
234
|
+
down
|
235
|
+
end
|
236
|
+
end
|
237
|
+
end
|
238
|
+
|
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
|
+
# Get the timeout, in seconds, for this node.
|
248
|
+
#
|
249
|
+
# @example Get the timeout in seconds.
|
250
|
+
# node.timeout
|
251
|
+
#
|
252
|
+
# @return [ Integer ] The configured timeout or the default of 5.
|
253
|
+
#
|
254
|
+
# @since 1.0.0
|
255
|
+
def timeout
|
256
|
+
@timeout ||= (options[:timeout] || 5)
|
257
|
+
end
|
258
|
+
|
259
|
+
private
|
260
|
+
|
261
|
+
# Yield the block with logging.
|
262
|
+
#
|
263
|
+
# @api private
|
264
|
+
#
|
265
|
+
# @example Yield with logging.
|
266
|
+
# logging(operations) do
|
267
|
+
# node.command(ismaster: 1)
|
268
|
+
# end
|
269
|
+
#
|
270
|
+
# @param [ Array<Message> ] operations The operations.
|
271
|
+
#
|
272
|
+
# @return [ Object ] The result of the yield.
|
273
|
+
#
|
274
|
+
# @since 2.0.0
|
275
|
+
def logging(message)
|
276
|
+
instrument(TOPIC, prefix: " BONES-RPC: #{address.resolved}", ops: [message]) do
|
277
|
+
yield if block_given?
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
def next_request_id
|
282
|
+
@request_id += 1
|
283
|
+
if @request_id >= 1 << 31
|
284
|
+
@request_id = 0
|
285
|
+
end
|
286
|
+
@request_id
|
287
|
+
end
|
288
|
+
|
289
|
+
def next_synack_id
|
290
|
+
@synack_id += 1
|
291
|
+
if @synack_id >= (1 << 32) - 1
|
292
|
+
@synack_id = 0
|
293
|
+
end
|
294
|
+
@synack_id
|
295
|
+
end
|
296
|
+
|
297
|
+
def process(message, future = nil)
|
298
|
+
logging(message) do
|
299
|
+
ensure_connected do
|
300
|
+
@connection.write([[message, future]])
|
301
|
+
end
|
302
|
+
end
|
303
|
+
return future
|
304
|
+
rescue Exception => e
|
305
|
+
abort(e)
|
306
|
+
end
|
307
|
+
|
308
|
+
def with_future(message)
|
309
|
+
process(message, Future.new)
|
310
|
+
end
|
311
|
+
|
312
|
+
def without_future(message)
|
313
|
+
process(message, nil)
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
end
|