Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DOCSP-4466 Add CSOT #951

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
3 changes: 3 additions & 0 deletions .github/workflows/vale-tdbx.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ jobs:
steps:
- name: checkout
uses: actions/checkout@master

- name: Install docutils
run: sudo apt-get install -y docutils

- id: files
uses: masesgroup/retrieve-changed-files@v2
Expand Down
22 changes: 22 additions & 0 deletions source/code-snippets/connection/csot-operation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { MongoClient } from "mongodb";

// start-operation
const uri = "<connection string uri>";
const client = new MongoClient(uri, {
timeoutMS: 10000
});

async function run() {
try {
const db = client.db("test-db");
const coll = db.collection("test-collection");

const result = await coll.insertOne({ name: "Yngwie" });
console.log("Insert result:", result);
} finally {
await client.close();
}
}

run().catch(console.dir);
// end-operation
31 changes: 31 additions & 0 deletions source/code-snippets/connection/csot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { MongoClient } from "mongodb";

const { MongoClient } = require('mongodb');

//start-csot
// Creates a new MongoClient with a client-level timeoutMS configuration
const uri = "<connection string uri>";
const client = new MongoClient(uri, {
// Client-level timeout: 15 seconds
timeoutMS: 15000
});

async function run() {
try {
const db = client.db("test-db");
const coll = db.collection("test-collection");

// Performs a query operation with an operation-level timeoutMS configuration
const docs = await coll.find({},
// Operation-level timeout: 10 seconds
{ timeoutMS: 10000 })
.toArray();

console.log(docs);
} finally {
await client.close();
}
}

run().catch(console.dir);
//end-csot
2 changes: 2 additions & 0 deletions source/fundamentals/connection.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Connection
Network Compression </fundamentals/connection/network-compression>
TLS </fundamentals/connection/tls>
SOCKS5 Proxy Support </fundamentals/connection/socks>
Limit Server Execution Time </fundamentals/connection/csot>
Connect with AWS Lambda <https://www.mongodb.com/docs/atlas/manage-connections-aws-lambda/>

.. contents:: On this page
Expand All @@ -41,6 +42,7 @@ learn:
- :ref:`How to Enable Network Compression <node-network-compression>`
- :ref:`How to Enable TLS on a Connection <node-connect-tls>`
- :ref:`How to Enable SOCKS5 Proxy Support <node-connect-socks>`
- :ref:`How to Limit Server Execution Time <node-csot>`
- :atlas:`How to Connect to MongoDB Atlas from AWS Lambda </manage-connections-aws-lambda/>`

Compatibility
Expand Down
225 changes: 225 additions & 0 deletions source/fundamentals/connection/csot.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,225 @@
.. _node-csot:

Limit Server Execution Time
===========================

.. contents:: On this page
:local:
:backlinks: none
:depth: 2
:class: singlecol

.. facet::
:name: genre
:values: reference

.. meta::
:keywords: error, blocking, thread, task

Overview
--------

When you use {+driver-short+} to perform a server operation, you can also limit
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
When you use {+driver-short+} to perform a server operation, you can also limit
When you use the {+driver-short+} to perform a server operation, you can also limit

S: I think we normally put 'the' in front of the the driver name!

the duration allowed for the server to finish the operation. To do so,
specify a **client-side operation timeout**. The timeout applies to all steps
stephmarie17 marked this conversation as resolved.
Show resolved Hide resolved
needed to complete the operation, including server selection, connection
checkout, serialization, and server-side execution. When the timeout expires,
{+driver-short+} raises a timeout exception.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
{+driver-short+} raises a timeout exception.
the {+driver-short+} raises a timeout exception.

the


You can specify a timeout by using the ``timeoutMS`` option.
stephmarie17 marked this conversation as resolved.
Show resolved Hide resolved

.. note:: Experimental Feature

The Client-Side Operation Timeout (CSOT) feature is experimental and might
stephmarie17 marked this conversation as resolved.
Show resolved Hide resolved
change in future driver releases.

timeoutMS Option
----------------

You can specify the ``timeoutMS`` option in your ``MongoClientOptions``
instance or at the database, collection, session, transaction, or operation
levels.

To specify a timeout when connecting to a MongoDB deployment, set the
``timeoutMS`` connection option to the timeout length in milliseconds.
stephmarie17 marked this conversation as resolved.
Show resolved Hide resolved

The following code example uses the ``timeoutMS`` option to specify a timeout of
10 seconds when instantiating a new ``MongoClient`` instance:

.. code-block:: javascript

const uri = "mongodb://<db_username>:<db_password>@<hostname:<port>";
stephmarie17 marked this conversation as resolved.
Show resolved Hide resolved
const client = new MongoClient(uri, {
timeoutMS: 10000
});

When you specify the ``timeoutMS`` option, it always takes precedence over the
following options:

- ``socketTimeoutMS``
- ``waitQueueTimeoutMS``
- ``wTimeoutMS``
- ``maxTimeMS``
- ``maxCommitTimeMS``

.. note:: Experimental Feature

When the CSOT feature is no longer experimental, the preceding options will
be deprecated. The ``timeoutMS`` option will superse the older, deprecated
options.
stephmarie17 marked this conversation as resolved.
Show resolved Hide resolved

If you specify the ``timeoutMS`` option, the driver automatically applies the
specified timeout to each server operation. The following code example specifies
Comment on lines +65 to +66
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

q: i thought the timeout applied to the total time for all operations in the aggregate. does this depend on the level at which you specify it?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's been awhile since I initially wrote this but if I recall correctly this was how CSOT is also described in the PyMongo doc so I carried this intro over but will see if there is a better way to describe this during technical review!

a timeout limit of 10 seconds at the collection level, and then calls the
``insertOne()`` method:

.. literalinclude:: /code-snippets/connection/csot-operation.js
:language: javascript
:start-after: start-operation
:end-before: end-operation

Inheritance Behavior
~~~~~~~~~~~~~~~~~~~~
stephmarie17 marked this conversation as resolved.
Show resolved Hide resolved

When you specify a ``timeoutMS`` option, the driver applies the timeout
according to the same inheritance behaviors as other {+driver-short+} options.
Copy link
Collaborator

@lindseymoore lindseymoore Jan 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
according to the same inheritance behaviors as other {+driver-short+} options.
according to the same inheritance behaviors as the other {+driver-short+} options.

S: Could put 'the' here as well, since you're talking about a specific set of options mentioned previously

The following list describes how the timeout value is inherited at each level:

- **Operation Level**: Takes the highest precedence and will override ``timeoutMS``
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if this order is hierarchical, it might make more sense as a numbered list to clearly show precedence.

it could also be helpful to word every list entry in the same way. e.g.: 'Applies to X. Can be overridden by Y.' you could also structure it as a table if you like the look of it.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated it to be a table I kind of think that makes it easier to skim lmk what you think!

options set at any other level.

- **Transaction Level**: Takes precedence over ``timeoutMS`` set at the session,
collection, database, or client level.

- **Session Level**: Inherits to all transactions and operations within
that session, unless the option is overridden by options set at those levels.

- **Collection Level**: Inherits to all sessions and operations on that
stephmarie17 marked this conversation as resolved.
Show resolved Hide resolved
collection, unless the option is overridden by options set at those levels.

- **Database Level**: Applies to all collections within that database. It is
inherited by all sessions, collections, and operations within the collections
on that database, unless the option is overridden by an option set at a level
with higher precedence.

- **Client Level**: Applies to all databases, collections, sessions,
transactions, and operations within that client that do not otherwise specify
``timeoutMS``.

For more information on overrides and specific options, see the :ref:`Overrides
<node-csot-overrides>` section.

.. _node-csot-overrides:

Overrides
---------

The Node.js driver supports various levels of configuration to control the
stephmarie17 marked this conversation as resolved.
Show resolved Hide resolved
behavior and performance of database operations.

You can specify a ``timeoutMS`` option at the operation level to override the
client-level configuration for a specific operation. This allows you to
customize timeouts based on the needs of individual queries.

The following example demonstrates how an operation-level ``timeoutMS``
configuration can override a client-level ``timeoutMS`` configuration:

.. literalinclude:: /code-snippets/connection/csot.js
:language: javascript
:start-after: start-csot
:end-before: end-csot

Transactions
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

q: can you help me understand the relationship between Overrides / Transactions / Client Encryption? it almost seems like overrides should be appended to the previous section on inheritance.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I was debating how to organize this and actually ended up adding the inheritance section after writing these for additional clarity around the expected behavior. I added that as a subsection thinking it was more connected to the option, while the Overrides section calls out some behavior specific to the example use case, transactions, and client encryption. Mostly based on what was requested in the ticket. Does this make sense as is or do you think it needs further tweaking on the section headings?

~~~~~~~~~~~~

When you create a new ``ClientSession`` instance to implement a transaction, use
the ``defaultTimeoutMS`` option. You can set ``defaultTimeoutMS`` to specify the
``timeoutMS`` values to use for:

- `commitTransaction()
<{+api+}/classes/ClientSession.html#commitTransaction>`__
- `abortTransaction()
<{+api+}/classes/ClientSession.html#abortTransaction>`__
- `withTransaction() <{+api+}/classes/ClientSession.html#withTransaction>`__
- `endSession()
<{+api+}/classes/ClientSession.html#endSession>`__

If you do not specify ``defaultTimeoutMS``, the driver uses the ``timeoutMS``
value set on the parent ``MongoClient``.

You cannot override ``defaultTimeoutMS`` by setting the ``timeoutMS`` option on an
operation in a transaction session provided by the ``withTransaction()`` callback.
Doing so throws an error.

Client Encryption
~~~~~~~~~~~~~~~~~

When you use Client-Side Field Level Encryption (CSFLE), the driver uses the
``timeoutMS`` option to limit the time allowed for encryption and decryption
operations.

If you specify the ``timeoutMS`` option when you construct a
``ClientEncryption`` instance, it controls the lifetime of all operations
performed on that instance. If you do not provide ``timeoutMS``, the instance
inherits the ``timeoutMS`` setting from the ``MongoClient`` used in the
``ClientEncryption`` constructor.

If you set ``timeoutMS`` on both the client and directly in
``ClientEncryption``, the value provided to ``ClientEncryption`` takes
precedence.

Cursors
-------

Cursors require special handling when you use the CSOT feature. The
``timeOutMS`` option is configurable on a per-cursor basis. You can configure
cursors to interact with CSOT by using etiher the cursor lifetime or cursor
iteration mode.
stephmarie17 marked this conversation as resolved.
Show resolved Hide resolved

Cursor Lifetime Mode
~~~~~~~~~~~~~~~~~~~~

The ``cursorLifetime`` mode uses ``timeoutMS`` to bound the entire lifetime of a
stephmarie17 marked this conversation as resolved.
Show resolved Hide resolved
stephmarie17 marked this conversation as resolved.
Show resolved Hide resolved
cursor. This is the default timeout mode for non-tailable cursors, such as
``find()``, ``aggregate()``, or ``listCollections()``. In this mode, the initialization
stephmarie17 marked this conversation as resolved.
Show resolved Hide resolved
of the cursor and all subsequent ``getMore()`` calls must finish within the limit
stephmarie17 marked this conversation as resolved.
Show resolved Hide resolved
specified with ``timeoutMS``. If they do not, the system throws a timeout error.
stephmarie17 marked this conversation as resolved.
Show resolved Hide resolved

Closing a cursor, either as part of a ``toArray()`` call or manually using the
``close()`` method, resets the timeout.
stephmarie17 marked this conversation as resolved.
Show resolved Hide resolved

Set the ``timeoutMS`` option to ensure the cursor initialization and retrieval
of all documents occur within 10 seconds, as shown in the following example:
stephmarie17 marked this conversation as resolved.
Show resolved Hide resolved

.. code-block:: javascript

const docs = await collection.find({}, {timeoutMS: 10000}).toArray();

Cursor Iteration Mode
~~~~~~~~~~~~~~~~~~~~~

The iteration mode uses ``timeoutMS`` to bind each ``next()``, ``hasNext()``, or
stephmarie17 marked this conversation as resolved.
Show resolved Hide resolved
``tryNext()`` call. The timeout refreshes after each call completes. This is the
stephmarie17 marked this conversation as resolved.
Show resolved Hide resolved
default mode for all tailable cursors, such as tailable ``find()`` cursors on
capped collections or change streams.
stephmarie17 marked this conversation as resolved.
Show resolved Hide resolved

As shown in the following example, the cursor continues to fetch new documents
as they are added to a collection, and then times out if it takes longer than 10
seconds to retrieve documents:
Comment on lines +208 to +210
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
As shown in the following example, the cursor continues to fetch new documents
as they are added to a collection, and then times out if it takes longer than 10
seconds to retrieve documents:
As shown in the following example, the cursor continues to fetch new documents
as they are added to a collection and times out if it takes longer than 10
seconds to retrieve documents:

S: Don't think that second clause is independent, so I removed the comma and 'then'. Could also separate into two sentences.
Style Guide on 'then' : https://www.mongodb.com/docs/meta/style-guide/terminology/alphabetical-terms/#t


.. code-block:: javascript

for await (const doc of cappedCollection.find({},
{tailable: true, timeoutMS: 10000})) {
// Handle each document
};

API Documentation
-----------------

To learn more about using timeouts with the {+driver-short+}, see the following
API documentation:

- `MongoClient <{+api+}/classes/MongoClient.html>`__
- `timeoutMS <{+api+}/classes/MongoClient.html#timeoutMS>`__
- `ClientSession <{+api+}/classes/ClientSession.html>`__
Loading