Skip to content

Commit

Permalink
RUBY-3284 Enable max_connecting client option (#2739)
Browse files Browse the repository at this point in the history
* RUBY-3284 Enable max_connecting client option

* Add validation and error

* Add test for uri option

* More tests

* Docu; bump the version

* Fix connection_requests counter handling

* Fix code review remarks

* Increase timeout

* Update documentation

* Housekeeping

* Update release-notes.txt

* Fix code review remarks

* Revert some changes in spec tests

* Skip flaky jruby test

* Use select (we still support 2.5)

---------

Co-authored-by: Alex Bevilacqua <[email protected]>
  • Loading branch information
comandeo-mongo and alexbevi authored Jul 13, 2023
1 parent c928e60 commit 7f338a1
Show file tree
Hide file tree
Showing 12 changed files with 254 additions and 53 deletions.
26 changes: 25 additions & 1 deletion docs/reference/create-client.txt
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,11 @@ Ruby Options
- ``Object``
- ``Logger``

* - ``:max_connecting``
- The maximum number of connections that the connection pool will try to establish in parallel.
- ``Integer``
- 2

* - ``:max_idle_time``
- The maximum time, in seconds, that a connection can be idle before it
is closed by the connection pool.
Expand Down Expand Up @@ -1018,6 +1023,9 @@ URI options are explained in detail in the :manual:`Connection URI reference
* - localThresholdMS=Integer
- ``:local_threshold => Float``

* - maxConnecting=Integer
- ``:max_connecting => Integer``

* - maxIdleTimeMS=Integer
- ``:max_idle_time => Float``

Expand Down Expand Up @@ -1551,6 +1559,14 @@ maximum size, the thread waits for a connection to be returned to the pool by
another thread. If ``max_pool_size`` is set to zero, there is no limit for the
maximum number of connections in the pool.

Each pool has a limit on the number of connections that can be concurrently
connecting to a server. This limit is called ``max_connecting`` and defaults to
2. If the number of connections that are currently connecting to a server
reaches this limit, the pool will wait for a connection attempt to succeed or
fail before attempting to create a new connection. If your application
has a large number of threads, you may want to increase ``max_connecting`` to avoid
having threads wait for a connection to be established.

The number of seconds the thread will wait for a connection to become available
is configurable. This setting, called ``wait_queue_timeout``, is defined in
seconds. If this timeout is reached, a ``Timeout::Error`` is raised. The
Expand Down Expand Up @@ -1595,6 +1611,14 @@ process, increase ``max_pool_size``:

client = Mongo::Client.new(["localhost:27017"], max_pool_size: 200)

To support extremely high numbers of threads that share the same client
within one process, increase ``max_connecting``:

.. code-block:: ruby

client = Mongo::Client.new(["localhost:27017"], max_pool_size: 200, max_connecting: 10)


Any number of threads are allowed to wait for connections to become available,
and they can wait the default (1 second) or the ``wait_queue_timeout`` setting:

Expand Down Expand Up @@ -1627,7 +1651,7 @@ such as Unicorn, Puma or Passenger, or when the application otherwise forks,
each process should generally each have their own ``Mongo::Client`` instances.
This is because:

1. The background threads remain in the parent process and are not transfered
1. The background threads remain in the parent process and are not transferred
to the child process.
2. File descriptors like network sockets are shared between parent and
child processes.
Expand Down
6 changes: 6 additions & 0 deletions docs/release-notes.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ now supports Ruby 3.2. Ruby 2.5 and 2.6 are now deprecated.

This release includes the following new features:

- The driver now limits the number of connections established by a connection
pool simultaneously. By default the limit is 2. The limit can be configured
with the ``:max_connecting`` option of the ``Mongo::Client`` constructor.
The default should be sufficient for most applications. However, if your
application is using a large number of threads, you may need to increase
the limit.
- Added support for automatic AWS credentials retrieval and authentication
with temporary credentials when AWS KMS is used for client side encryption.
- Added support for automatic GCP credentials retrieval when Google Cloud Key
Expand Down
25 changes: 25 additions & 0 deletions lib/mongo/client.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class Client
:local_threshold,
:logger,
:log_prefix,
:max_connecting,
:max_idle_time,
:max_pool_size,
:max_read_retries,
Expand Down Expand Up @@ -266,6 +267,12 @@ def hash
# @option options [ String ] :log_prefix A custom log prefix to use when
# logging. This option is experimental and subject to change in a future
# version of the driver.
# @option options [ Integer ] :max_connecting The maximum number of
# connections that can be connecting simultaneously. The default is 2.
# This option should be increased if there are many threads that share
# the same client and the application is experiencing timeouts
# while waiting for connections to be established.
# selecting a server for an operation. The default is 2.
# @option options [ Integer ] :max_idle_time The maximum seconds a socket can remain idle
# since it has been checked in to the pool.
# @option options [ Integer ] :max_pool_size The maximum size of the
Expand Down Expand Up @@ -1318,6 +1325,7 @@ def validate_new_options!(opts)
key = k.to_sym
if VALID_OPTIONS.include?(key)
validate_max_min_pool_size!(key, opts)
validate_max_connecting!(key, opts)
validate_read!(key, opts)
if key == :compressors
compressors = valid_compressors(v)
Expand Down Expand Up @@ -1580,6 +1588,23 @@ def validate_max_min_pool_size!(option, opts)
true
end

# Validates whether the max_connecting option is valid.
#
# @param [ Symbol ] option The option to validate.
# @param [ Hash ] opts The client options.
#
# @return [ true ] If the option is valid.
# @raise [ Error::InvalidMaxConnecting ] If the option is invalid.
def validate_max_connecting!(option, opts)
if option == :max_connecting && opts.key?(:max_connecting)
max_connecting = opts[:max_connecting] || Server::ConnectionPool::DEFAULT_MAX_CONNECTING
if max_connecting <= 0
raise Error::InvalidMaxConnecting.new(opts[:max_connecting])
end
end
true
end

def validate_read!(option, opts)
if option == :read && opts.has_key?(:read)
read = opts[:read]
Expand Down
1 change: 1 addition & 0 deletions lib/mongo/error.rb
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ def write_concern_error_labels
require 'mongo/error/invalid_document'
require 'mongo/error/invalid_file'
require 'mongo/error/invalid_file_revision'
require 'mongo/error/invalid_max_connecting'
require 'mongo/error/invalid_min_pool_size'
require 'mongo/error/invalid_read_option'
require 'mongo/error/invalid_application_name'
Expand Down
28 changes: 28 additions & 0 deletions lib/mongo/error/invalid_max_connecting.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# frozen_string_literal: true

# Copyright (C) 2014-present MongoDB Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

module Mongo
class Error
# Exception that is raised when trying to create a client with an invalid
# max_connecting option.
class InvalidMaxConnecting < Error
# Instantiate the new exception.
def initialize(max_connecting)
super("Invalid max_connecting: #{max_connecting}. Please ensure that it is greater than zero. ")
end
end
end
end
Loading

0 comments on commit 7f338a1

Please sign in to comment.