Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 124 additions & 41 deletions docs/tutorials/ruby-driver-create-client.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,68 +14,142 @@ Using ``Mongo::Client``
-----------------------

To connect to a MongoDB deployment, create a ``Mongo::Client`` object.
Provide a list of hosts and options or a connection URI to the
``Mongo::Client`` constructor. The client's selected database
defaults to ``admin``.
Provide a list of hosts and options or a :manual:`connection string URI
</reference/connection-string/>` to the``Mongo::Client`` constructor.
The client's selected database defaults to ``admin``.

To create a client to a standalone server, provide one host in the
seed list. Optionally, you can force the cluster topology to be
standalone without going through the auto-discovery steps.
By default, the driver will automatically detect the topology used by the
deployment and connect appropriately.

To connect to a local standalone MongoDB deployment, specify the host and
port as follows:

.. code-block:: ruby

Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'mydb')
Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'mydb', :connect => :direct)
Mongo::Client.new('mongodb://127.0.0.1:27017/mydb')
Mongo::Client.new([ '127.0.0.1:27017' ], database: 'mydb')

# Or using the URI syntax:
Mongo::Client.new("mongodb://127.0.0.1:27017/mydb")

.. note::

The hostname ``localhost`` is treated specially by the driver and will
be resolved to IPv4 addresses only.

To `connect to MongoDB Atlas <https://docs.atlas.mongodb.com/driver-connection/>`,
specify the Atlas deployment URI:

.. code-block:: ruby

Mongo::Client.new("mongodb+srv://username:myRealPassword@cluster0.mongodb.net/test?w=majority")

The driver will discover all nodes in the cluster and connect to them as
needed.


Direct Connection
`````````````````

If the deployment is a replica set, the driver will by default discover all
members of the replica set given the address of any one member, and will
dispatch operations to the appropriate member (for example, writes would be
dispatched to the primary).

To force all operations to be performed on the designated server, specify the
``direct_connection`` option:

.. code-block:: ruby

Mongo::Client.new([ '1.2.3.4:27017' ], database: 'mydb', direct_connection: true)

# Or using the URI syntax:
Mongo::Client.new("mongodb://1.2.3.4:27017/mydb?directConnection=true")


.. _ruby-driver-connect-replica-set:

To connect to a :manual:`replica set</replication/>`,
pass one or more hosts and the replica set name.
The driver's auto-discovery feature finds all members of the replica
set if they are not all provided.
Replica Set Connection
``````````````````````

To connect to a :manual:`replica set</replication/>` deployment managed by a
service providing SRV URIs (such as MongoDB Atlas), connect to the URI:

.. code-block:: ruby

Mongo::Client.new([ '127.0.0.1:27017', '127.0.0.1:27018' ], :database => 'mydb', replica_set: 'myapp')
Mongo::Client.new('mongodb://127.0.0.1:27017,127.0.0.1:27018/mydb?replicaSet=myapp')
Mongo::Client.new("mongodb+srv://username:myRealPassword@cluster0.mongodb.net/test?w=majority")

If not using SRV URIs, it is sufficient to pass the address of any node in the
replica set to the driver; the driver will then automatically discover the
remaining nodes. However, it is recommended to specify all nodes that are part
of the replica set, so that in the event of one or more nodes being unavailable
(for example, due to maintenance or reconfiguration) the driver can still
connect to the replica set.

.. code-block:: ruby

Mongo::Client.new([ '127.0.0.1:27017', '127.0.0.1:27018' ],
:database => 'mydb', replica_set: 'myapp')

# Or using the URI syntax:
Mongo::Client.new("mongodb://127.0.0.1:27017,127.0.0.1:27018/mydb?replicaSet=myapp")


.. _ruby-driver-connect-sharded-cluster:

To create a client to a :manual:`sharded cluster</sharding/>`,
pass one or more :manual:`mongos</reference/program/mongos/>`
hosts. The auto-discovery feature can determine that the
servers are ``mongos`` instances, but if you
would like to bypass the auto-discovery, pass the
``sharded`` option to the client.
Sharded Cluster Connection
``````````````````````````

To connect to a :manual:`sharded cluster</sharding/>` deployment managed by a
service providing SRV URIs (such as MongoDB Atlas), connect to the URI:

.. code-block:: ruby

Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'mydb')
Mongo::Client.new([ '127.0.0.1:27017' ], :database => 'mydb', :connect => :sharded)
Mongo::Client.new('mongodb://127.0.0.1:27017/mydb?connect=sharded')
Mongo::Client.new("mongodb+srv://username:myRealPassword@cluster0.mongodb.net/test?w=majority")

The URI parser in the driver also accepts the
:manual:`mongodb+srv protocol <reference/connection-string/#dns-seedlist-connection-format>`
URIs, for example:
When the driver connects to a sharded cluster via an SRV URI, it will monitor
the SRV records of the address specified in the URI for changes and will
automatically add and remove ``mongos`` hosts to/from its list of servers as
they are added and removed to/from the sharded cluster.

If not using SRV URIs, pass the addresses of one or more
:manual:`mongos</reference/program/mongos/>` hosts. Unlike with
replica set deployments, the driver is not able to discover all ``mongos``
nodes in a sharded cluster when not using SRV URIs. It is not required that all
``mongos`` node addresses are given to the driver - the driver will balance
the operation load among the nodes it is given. Specifying more nodes will
spread the operation load accordingly.

.. code-block:: ruby

Mongo::Client.new('mongodb+srv://test5.test.build.mongodb.cc')
Mongo::Client.new([ '1.2.3.4:27017', '1.2.3.5:27017' ], :database => 'mydb')

Mongo::Client.new("mongodb://1.2.3.4:27017,1.2.3.5:27017/mydb")

When an SRV URI is given, the driver does the following:

1. As part of ``Client`` object construction, the SRV URI is resolved to
the actual hosts comprising the deployment, as these are defined in the DNS
SRV records.
SRV URIs
````````

When the driver connects to a
:manual:`mongodb+srv protocol <reference/connection-string/#dns-seedlist-connection-format>`
URI, keep in mind the following:

1. SRV URI lookup is performed synchronously when the client is constructed.
If this lookup fails for any reason, client construction will fail with an
exception. When a client is constructed with a list of hosts, the driver
will attempt to contact and monitor those hosts for as long as the client
object exists. If one of these hosts does not resolve initially but becomes
resolvable later, the driver will be able to establish a connection to such
a host when it becomes available. The initial SRV URI lookup must succeed
on the first attempt; subsequent host lookups will be retried by the driver
as needed.
2. The driver looks up URI options in the DNS TXT records corresponding to the
SRV records. These options can be overridden by URI options specified in the
URI and by Ruby options, in this order.
SRV records. These options can be overridden by URI options specified in the
URI and by Ruby options, in this order.
3. If the topology of the constructed ``Client`` object is unknown or a
sharded cluster, the driver will begin monitoring the specified SRV DNS
records for changes and will automatically update the list of servers in the
cluster. The updates will stop if the topology becomes a single or a replica
set.
sharded cluster, the driver will begin monitoring the specified SRV DNS
records for changes and will automatically update the list of servers in the
cluster. The updates will stop if the topology becomes a single or a replica
set.


.. _ruby-driver-client-options:
Expand Down Expand Up @@ -148,9 +222,9 @@ Ruby Options
- none

* - ``:connect``
- Overrides the auto-discovery feature of the driver and forces the cluster
topology to a specific type. Choices: ``:direct``,
``:replica_set`` or ``:sharded``.
- **Deprecated.** Disables deployment topology discovery normally
performed by the dirver and forces the cluster topology to a specific
type. Choices: ``:direct``, ``:replica_set`` or ``:sharded``.
- ``Symbol``
- none

Expand All @@ -165,6 +239,12 @@ Ruby Options
- ``String``
- admin

* - ``:direct_connection``
- Connect directly to the specified host, do not discover deployment
topology.
- ``Boolean``
- false

* - ``:heartbeat_frequency``
- The number of seconds for the server monitors to refresh
server states asynchronously.
Expand Down Expand Up @@ -504,6 +584,9 @@ URI options are explained in detail in the :manual:`Connection URI reference
* - connectTimeoutMS=Integer
- ``:connect_timeout => Float``

* - directConnection=Boolean
- ``:direct_connection => Boolean``

* - fsync=Boolean
- ``{ :write_concern => { :fsync => true|false }}``

Expand Down
30 changes: 26 additions & 4 deletions lib/mongo/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class Client
:auto_encryption_options,
:cleanup,
:compressors,
:direct_connection,
:connect,
:connect_timeout,
:database,
Expand Down Expand Up @@ -205,7 +206,6 @@ def hash
# connection string is also provided, these options take precedence over any
# analogous options present in the URI string.
#
#
# @option options [ String, Symbol ] :app_name Application name that is
# printed to the mongod logs upon establishing a connection in server
# versions >= 3.4.
Expand All @@ -217,7 +217,11 @@ def hash
# compressors to use, in order of preference. The driver chooses the
# first compressor that is also supported by the server. Currently the
# driver only supports 'zlib'.
# @option options [ Symbol ] :connect The connection method to use. This
# @option options [ true | false ] :direct_connection Whether to connect
# directly to the specified seed, bypassing topology discovery. Exactly
# one seed must be provided.
# @option options [ Symbol ] :connect Deprecated - use :direct_connection
# option instead of this option. The connection method to use. This
# forces the cluster to behave in the specified way instead of
# auto-discovering. One of :direct, :replica_set, :sharded
# @option options [ Float ] :connect_timeout The timeout, in seconds, to
Expand Down Expand Up @@ -456,7 +460,7 @@ def initialize(addresses_or_uri, options = nil)
end
=end
@options.freeze
validate_options!
validate_options!(addresses)
validate_authentication_options!

@database = Database.new(self, @options[:database], @options)
Expand Down Expand Up @@ -998,10 +1002,28 @@ def validate_new_options!(opts = Options::Redacted.new)
# Validates all options after they are set on the client.
# This method is intended to catch combinations of options which are
# not allowed.
def validate_options!
def validate_options!(addresses = nil)
if options[:write] && options[:write_concern] && options[:write] != options[:write_concern]
raise ArgumentError, "If :write and :write_concern are both given, they must be identical: #{options.inspect}"
end

if options[:direct_connection]
if options[:connect] && options[:connect].to_sym != :direct
raise ArgumentError, "Conflicting client options: direct_connection=true and connect=#{options[:connect]}"
end
# When a new client is created, we get the list of seed addresses
if addresses && addresses.length > 1
raise ArgumentError, "direct_connection=true cannot be used with multiple seeds"
end
# When a client is copied using #with, we have a cluster
if cluster && !cluster.topology.is_a?(Mongo::Cluster::Topology::Single)
raise ArgumentError, "direct_connection=true cannot be used with topologies other than Single (this client is #{cluster.topology.class.name.sub(/.*::/, '')})"
end
end

if options[:direct_connection] == false && options[:connect] && options[:connect].to_sym == :direct
raise ArgumentError, "Conflicting client options: direct_connection=false and connect=#{options[:connect]}"
end
end

# Validates all authentication-related options after they are set on the client
Expand Down
10 changes: 10 additions & 0 deletions lib/mongo/cluster.rb
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,16 @@ class Cluster
# @param [ Hash ] options Options. Client constructor forwards its
# options to Cluster constructor, although Cluster recognizes
# only a subset of the options recognized by Client.
#
# @option options [ true | false ] :direct_connection Whether to connect
# directly to the specified seed, bypassing topology discovery. Exactly
# one seed must be provided.
# @option options [ Symbol ] :connect Deprecated - use :direct_connection
# option instead of this option. The connection method to use. This
# forces the cluster to behave in the specified way instead of
# auto-discovering. One of :direct, :replica_set, :sharded
# @option options [ Symbol ] :replica_set The name of the replica set to
# connect to. Servers not in this replica set will be ignored.
# @option options [ true | false ] :scan Whether to scan all seeds
# in constructor. The default in driver version 2.x is to do so;
# driver version 3.x will not scan seeds in constructor. Opt in to the
Expand Down
6 changes: 3 additions & 3 deletions lib/mongo/cluster/sdam_flow.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,14 +111,14 @@ def server_description_changed
when Topology::Sharded
unless updated_desc.unknown? || updated_desc.mongos?
log_warn(
"Removing server #{updated_desc.address.to_s} because it is a #{updated_desc.server_type.to_s.upcase} and not a MONGOS"
"Removing server #{updated_desc.address.to_s} because it is of the wrong type (#{updated_desc.server_type.to_s.upcase}) - expected SHARDED"
)
remove
end
when Topology::ReplicaSetWithPrimary
if updated_desc.standalone? || updated_desc.mongos?
log_warn(
"Removing server #{updated_desc.address.to_s} because it is a #{updated_desc.server_type.to_s.upcase} and not a replica set member"
"Removing server #{updated_desc.address.to_s} because it is of the wrong type (#{updated_desc.server_type.to_s.upcase}) - expected a replica set member"
)
remove
check_if_has_primary
Expand All @@ -132,7 +132,7 @@ def server_description_changed
when Topology::ReplicaSetNoPrimary
if updated_desc.standalone? || updated_desc.mongos?
log_warn(
"Removing server #{updated_desc.address.to_s} because it is a #{updated_desc.server_type.to_s.upcase} and not a replica set member"
"Removing server #{updated_desc.address.to_s} because it is of the wrong type (#{updated_desc.server_type.to_s.upcase}) - expected a replica set member"
)
remove
elsif updated_desc.primary?
Expand Down
19 changes: 18 additions & 1 deletion lib/mongo/cluster/topology.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,29 @@ module Topology
# @param [ Monitoring ] monitoring The monitoring.
# @param [ Hash ] options The cluster options.
#
# @option options [ true | false ] :direct_connection Whether to connect
# directly to the specified seed, bypassing topology discovery. Exactly
# one seed must be provided.
# @option options [ Symbol ] :connect Deprecated - use :direct_connection
# option instead of this option. The connection method to use. This
# forces the cluster to behave in the specified way instead of
# auto-discovering. One of :direct, :replica_set, :sharded
# @option options [ Symbol ] :replica_set The name of the replica set to
# connect to. Servers not in this replica set will be ignored.
#
# @return [ ReplicaSet, Sharded, Single ] The topology.
#
# @since 2.0.0
# @api private
def initial(cluster, monitoring, options)
cls = if options.key?(:connect)
cls = if options[:direct_connection]
if options[:connect] && options[:connect] && options[:connect].to_sym != :direct
raise ArgumentError, "Conflicting topology options: direct_connection=true and connect=#{options[:connect]}"
end
Single
elsif options[:direct_connection] == false && options[:connect] && options[:connect].to_sym == :direct
raise ArgumentError, "Conflicting topology options: direct_connection=false and connect=#{options[:connect]}"
elsif options.key?(:connect)
OPTIONS.fetch(options[:connect].to_sym)
elsif options.key?(:replica_set) || options.key?(:replica_set_name)
ReplicaSetNoPrimary
Expand Down
Loading