Skip to content

Commit 7f338a1

Browse files
RUBY-3284 Enable max_connecting client option (#2739)
* 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 <alex@alexbevi.com>
1 parent c928e60 commit 7f338a1

File tree

12 files changed

+254
-53
lines changed

12 files changed

+254
-53
lines changed

docs/reference/create-client.txt

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -575,6 +575,11 @@ Ruby Options
575575
- ``Object``
576576
- ``Logger``
577577

578+
* - ``:max_connecting``
579+
- The maximum number of connections that the connection pool will try to establish in parallel.
580+
- ``Integer``
581+
- 2
582+
578583
* - ``:max_idle_time``
579584
- The maximum time, in seconds, that a connection can be idle before it
580585
is closed by the connection pool.
@@ -1018,6 +1023,9 @@ URI options are explained in detail in the :manual:`Connection URI reference
10181023
* - localThresholdMS=Integer
10191024
- ``:local_threshold => Float``
10201025

1026+
* - maxConnecting=Integer
1027+
- ``:max_connecting => Integer``
1028+
10211029
* - maxIdleTimeMS=Integer
10221030
- ``:max_idle_time => Float``
10231031

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

1562+
Each pool has a limit on the number of connections that can be concurrently
1563+
connecting to a server. This limit is called ``max_connecting`` and defaults to
1564+
2. If the number of connections that are currently connecting to a server
1565+
reaches this limit, the pool will wait for a connection attempt to succeed or
1566+
fail before attempting to create a new connection. If your application
1567+
has a large number of threads, you may want to increase ``max_connecting`` to avoid
1568+
having threads wait for a connection to be established.
1569+
15541570
The number of seconds the thread will wait for a connection to become available
15551571
is configurable. This setting, called ``wait_queue_timeout``, is defined in
15561572
seconds. If this timeout is reached, a ``Timeout::Error`` is raised. The
@@ -1595,6 +1611,14 @@ process, increase ``max_pool_size``:
15951611

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

1614+
To support extremely high numbers of threads that share the same client
1615+
within one process, increase ``max_connecting``:
1616+
1617+
.. code-block:: ruby
1618+
1619+
client = Mongo::Client.new(["localhost:27017"], max_pool_size: 200, max_connecting: 10)
1620+
1621+
15981622
Any number of threads are allowed to wait for connections to become available,
15991623
and they can wait the default (1 second) or the ``wait_queue_timeout`` setting:
16001624

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

1630-
1. The background threads remain in the parent process and are not transfered
1654+
1. The background threads remain in the parent process and are not transferred
16311655
to the child process.
16321656
2. File descriptors like network sockets are shared between parent and
16331657
child processes.

docs/release-notes.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ now supports Ruby 3.2. Ruby 2.5 and 2.6 are now deprecated.
2828

2929
This release includes the following new features:
3030

31+
- The driver now limits the number of connections established by a connection
32+
pool simultaneously. By default the limit is 2. The limit can be configured
33+
with the ``:max_connecting`` option of the ``Mongo::Client`` constructor.
34+
The default should be sufficient for most applications. However, if your
35+
application is using a large number of threads, you may need to increase
36+
the limit.
3137
- Added support for automatic AWS credentials retrieval and authentication
3238
with temporary credentials when AWS KMS is used for client side encryption.
3339
- Added support for automatic GCP credentials retrieval when Google Cloud Key

lib/mongo/client.rb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ class Client
7171
:local_threshold,
7272
:logger,
7373
:log_prefix,
74+
:max_connecting,
7475
:max_idle_time,
7576
:max_pool_size,
7677
:max_read_retries,
@@ -266,6 +267,12 @@ def hash
266267
# @option options [ String ] :log_prefix A custom log prefix to use when
267268
# logging. This option is experimental and subject to change in a future
268269
# version of the driver.
270+
# @option options [ Integer ] :max_connecting The maximum number of
271+
# connections that can be connecting simultaneously. The default is 2.
272+
# This option should be increased if there are many threads that share
273+
# the same client and the application is experiencing timeouts
274+
# while waiting for connections to be established.
275+
# selecting a server for an operation. The default is 2.
269276
# @option options [ Integer ] :max_idle_time The maximum seconds a socket can remain idle
270277
# since it has been checked in to the pool.
271278
# @option options [ Integer ] :max_pool_size The maximum size of the
@@ -1318,6 +1325,7 @@ def validate_new_options!(opts)
13181325
key = k.to_sym
13191326
if VALID_OPTIONS.include?(key)
13201327
validate_max_min_pool_size!(key, opts)
1328+
validate_max_connecting!(key, opts)
13211329
validate_read!(key, opts)
13221330
if key == :compressors
13231331
compressors = valid_compressors(v)
@@ -1580,6 +1588,23 @@ def validate_max_min_pool_size!(option, opts)
15801588
true
15811589
end
15821590

1591+
# Validates whether the max_connecting option is valid.
1592+
#
1593+
# @param [ Symbol ] option The option to validate.
1594+
# @param [ Hash ] opts The client options.
1595+
#
1596+
# @return [ true ] If the option is valid.
1597+
# @raise [ Error::InvalidMaxConnecting ] If the option is invalid.
1598+
def validate_max_connecting!(option, opts)
1599+
if option == :max_connecting && opts.key?(:max_connecting)
1600+
max_connecting = opts[:max_connecting] || Server::ConnectionPool::DEFAULT_MAX_CONNECTING
1601+
if max_connecting <= 0
1602+
raise Error::InvalidMaxConnecting.new(opts[:max_connecting])
1603+
end
1604+
end
1605+
true
1606+
end
1607+
15831608
def validate_read!(option, opts)
15841609
if option == :read && opts.has_key?(:read)
15851610
read = opts[:read]

lib/mongo/error.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ def write_concern_error_labels
159159
require 'mongo/error/invalid_document'
160160
require 'mongo/error/invalid_file'
161161
require 'mongo/error/invalid_file_revision'
162+
require 'mongo/error/invalid_max_connecting'
162163
require 'mongo/error/invalid_min_pool_size'
163164
require 'mongo/error/invalid_read_option'
164165
require 'mongo/error/invalid_application_name'
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# frozen_string_literal: true
2+
3+
# Copyright (C) 2014-present MongoDB Inc.
4+
#
5+
# Licensed under the Apache License, Version 2.0 (the "License");
6+
# you may not use this file except in compliance with the License.
7+
# You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
module Mongo
18+
class Error
19+
# Exception that is raised when trying to create a client with an invalid
20+
# max_connecting option.
21+
class InvalidMaxConnecting < Error
22+
# Instantiate the new exception.
23+
def initialize(max_connecting)
24+
super("Invalid max_connecting: #{max_connecting}. Please ensure that it is greater than zero. ")
25+
end
26+
end
27+
end
28+
end

0 commit comments

Comments
 (0)