lib/moped/cluster.rb in moped-1.2.6 vs lib/moped/cluster.rb in moped-1.2.7
- old
+ new
@@ -2,12 +2,13 @@
# The cluster represents a cluster of MongoDB server nodes, either a single
# node, a replica set, or a mongos server.
class Cluster
+ # @attribute [r] options The cluster options.
# @attribute [r] seeds The seeds the cluster was initialized with.
- attr_reader :seeds
+ attr_reader :options, :seeds
# Get the authentication details for the cluster.
#
# @example Get the authentication details.
# cluster.auth
@@ -28,10 +29,61 @@
# @since 1.2.0
def disconnect
nodes.each { |node| node.disconnect } and true
end
+ # Get the interval at which a node should be flagged as down before
+ # retrying.
+ #
+ # @example Get the down interval, in seconds.
+ # cluster.down_interval
+ #
+ # @return [ Integer ] The down interval.
+ #
+ # @since 1.2.7
+ def down_interval
+ options[:down_interval]
+ end
+
+ # Get the number of times an operation should be retried before raising an
+ # error.
+ #
+ # @example Get the maximum retries.
+ # cluster.max_retries
+ #
+ # @return [ Integer ] The max retries.
+ #
+ # @since 1.2.7
+ def max_retries
+ options[:max_retries]
+ end
+
+ # Get the interval in which the node list should be refreshed.
+ #
+ # @example Get the refresh interval, in seconds.
+ # cluster.refresh_interval
+ #
+ # @return [ Integer ] The refresh interval.
+ #
+ # @since 1.2.7
+ def refresh_interval
+ options[:refresh_interval]
+ end
+
+ # Get the operation retry interval - the time to wait before retrying a
+ # single operation.
+ #
+ # @example Get the retry interval, in seconds.
+ # cluster.retry_interval
+ #
+ # @return [ Integer ] The retry interval.
+ #
+ # @since 1.2.7
+ def retry_interval
+ options[:retry_interval]
+ end
+
# Initialize the new cluster.
#
# @example Initialize the cluster.
# Cluster.new([ "localhost:27017" ], down_interval: 20)
#
@@ -44,11 +96,13 @@
#
# @since 1.0.0
def initialize(hosts, options)
@options = {
down_interval: 30,
- refresh_interval: 300
+ max_retries: 30,
+ refresh_interval: 300,
+ retry_interval: 1
}.merge(options)
@seeds = hosts
@nodes = hosts.map { |host| Node.new(host) }
end
@@ -63,12 +117,12 @@
# @return [ Array<Node> ] the list of available nodes.
#
# @since 1.0.0
def nodes
current_time = Time.new
- down_boundary = current_time - @options[:down_interval]
- refresh_boundary = current_time - @options[:refresh_interval]
+ down_boundary = current_time - down_interval
+ refresh_boundary = current_time - refresh_interval
# Find the nodes that were down but are ready to be refreshed, or those
# with stale connection information.
needs_refresh, available = @nodes.partition do |node|
(node.down? && node.down_at < down_boundary) || node.needs_refresh?(refresh_boundary)
@@ -133,19 +187,18 @@
# @example Yield the primary to the block.
# cluster.with_primary do |node|
# # ...
# end
#
- # @param [ true, false ] retry_on_failure Whether to retry if an error was
- # raised.
+ # @param [ Integer ] retries The number of times to retry.
#
# @raises [ ConnectionFailure ] When no primary node can be found
#
# @return [ Object ] The result of the yield.
#
# @since 1.0.0
- def with_primary(retry_on_failure = true, &block)
+ def with_primary(retries = max_retries, &block)
if node = nodes.find(&:primary?)
begin
node.ensure_primary do
return yield node.apply_auth(auth)
end
@@ -153,14 +206,15 @@
# Fall through to the code below if our connection was dropped or the
# node is no longer the primary.
end
end
- if retry_on_failure
+ if retries > 0
# We couldn't find a primary node, so refresh the list and try again.
+ sleep(retry_interval)
refresh
- with_primary(false, &block)
+ with_primary(retries - 1, &block)
else
raise(
Errors::ConnectionFailure,
"Could not connect to a primary node for replica set #{inspect}"
)
@@ -173,19 +227,18 @@
# @example Yield the secondary to the block.
# cluster.with_secondary do |node|
# # ...
# end
#
- # @param [ true, false ] retry_on_failure Whether to retry if an error was
- # raised.
+ # @param [ Integer ] retries The number of times to retry.
#
# @raises [ ConnectionFailure ] When no primary node can be found
#
# @return [ Object ] The result of the yield.
#
# @since 1.0.0
- def with_secondary(retry_on_failure = true, &block)
+ def with_secondary(retries = max_retries, &block)
available_nodes = nodes.shuffle!.partition(&:secondary?).flatten
while node = available_nodes.shift
begin
return yield node.apply_auth(auth)
@@ -193,14 +246,15 @@
# That node's no good, so let's try the next one.
next
end
end
- if retry_on_failure
+ if retries > 0
# We couldn't find a secondary or primary node, so refresh the list and
# try again.
+ sleep(retry_interval)
refresh
- with_secondary(false, &block)
+ with_secondary(retries - 1, &block)
else
raise(
Errors::ConnectionFailure,
"Could not connect to any secondary or primary nodes for replica set #{inspect}"
)