# File 'lib/mongo/server_selector/base.rb', line 200
private def select_server_impl(cluster, ping, session, write_aggregation, deprioritized, csot_timeout)
if cluster.topology.is_a?(Cluster::Topology::LoadBalanced)
return cluster.servers.first
end
timeout = cluster.options[:server_selection_timeout] || SERVER_SELECTION_TIMEOUT
server_selection_timeout = if csot_timeout && csot_timeout > 0
[timeout, csot_timeout].min
else
timeout
end
if server_selection_timeout == 0
msg = "Failing server selection due to zero timeout. " +
" Requested #{name} in cluster: #{cluster.summary}"
raise Error::NoServerAvailable.new(self, cluster, msg)
end
deadline = Utils.monotonic_time + server_selection_timeout
if session && session.pinned_server
if Mongo::Lint.enabled?
unless cluster.sharded?
raise Error::LintError, "Session has a pinned server in a non-sharded topology: #{topology}"
end
end
if !session.in_transaction?
session.unpin
end
if server = session.pinned_server
unless server.mongos?
while (time_remaining = deadline - Utils.monotonic_time) > 0
wait_for_server_selection(cluster, time_remaining)
end
unless server.mongos?
msg = "The session being used is pinned to the server which is not a mongos: #{server.summary} " +
"(after #{server_selection_timeout} seconds)"
raise Error::NoServerAvailable.new(self, cluster, msg)
end
end
return server
end
end
if cluster.replica_set?
validate_max_staleness_value_early!
end
if cluster.addresses.empty?
if Lint.enabled?
unless cluster.servers.empty?
raise Error::LintError, "Cluster has no addresses but has servers: #{cluster.servers.map(&:inspect).join(', ')}"
end
end
msg = "Cluster has no addresses, and therefore will never have a server"
raise Error::NoServerAvailable.new(self, cluster, msg)
end
=begin Add this check in version 3.0.0
unless cluster.connected?
msg = 'Cluster is disconnected'
raise Error::NoServerAvailable.new(self, cluster, msg)
end
=end
loop do
if Lint.enabled?
cluster.servers.each do |server|
if !server.unknown? && !server.pool.ready?
raise Error::LintError, "Server #{server.summary} is known but has non-ready pool"
end
end
end
server = try_select_server(cluster, write_aggregation: write_aggregation, deprioritized: deprioritized)
if server
unless cluster.topology.compatible?
raise Error::UnsupportedFeatures, cluster.topology.compatibility_error.to_s
end
if session && session.starting_transaction? && cluster.sharded?
session.pin_to_server(server)
end
return server
end
cluster.scan!(false)
time_remaining = deadline - Utils.monotonic_time
if time_remaining > 0
wait_for_server_selection(cluster, time_remaining)
else
break
end
end
msg = "No #{name} server"
if is_a?(ServerSelector::Secondary) && !tag_sets.empty?
msg += " with tag sets: #{tag_sets}"
end
msg += " is available in cluster: #{cluster.summary} " +
"with timeout=#{server_selection_timeout}, " +
"LT=#{local_threshold_with_cluster(cluster)}"
msg += server_selection_diagnostic_message(cluster)
raise Error::NoServerAvailable.new(self, cluster, msg)
rescue Error::NoServerAvailable => e
if session && session.in_transaction? && !session.committing_transaction?
e.add_label('TransientTransactionError')
end
if session && session.committing_transaction?
e.add_label('UnknownTransactionCommitResult')
end
raise e
end