From a294bd1d70b53c53223851002bc4ef34222e2d28 Mon Sep 17 00:00:00 2001 From: Warren James Date: Thu, 24 Oct 2024 17:45:44 -0400 Subject: [PATCH 01/10] start API docs --- src/collection.ts | 3 +- src/cursor/abstract_cursor.ts | 54 +++++++++++++++++++++++++++++++---- src/db.ts | 3 +- src/error.ts | 1 - src/gridfs/index.ts | 2 +- src/mongo_client.ts | 4 +-- src/operations/indexes.ts | 2 -- src/operations/operation.ts | 2 +- 8 files changed, 54 insertions(+), 17 deletions(-) diff --git a/src/collection.ts b/src/collection.ts index e66a0cc16f5..9ce5049efe8 100644 --- a/src/collection.ts +++ b/src/collection.ts @@ -115,7 +115,7 @@ export interface CollectionOptions extends BSONSerializeOptions, WriteConcernOpt readConcern?: ReadConcernLike; /** The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST). */ readPreference?: ReadPreferenceLike; - /** @internal TODO(NODE-5688): make this public */ + /** Specifies the time an operation will run until it throws a timeout error */ timeoutMS?: number; } @@ -262,7 +262,6 @@ export class Collection { this.s.collectionHint = normalizeHintField(v); } - /** @internal */ get timeoutMS(): number | undefined { return this.s.options.timeoutMS; } diff --git a/src/cursor/abstract_cursor.ts b/src/cursor/abstract_cursor.ts index 4eb5904f433..dd2f4644af8 100644 --- a/src/cursor/abstract_cursor.ts +++ b/src/cursor/abstract_cursor.ts @@ -61,15 +61,36 @@ export interface CursorStreamOptions { /** @public */ export type CursorFlag = (typeof CURSOR_FLAGS)[number]; -/** @public*/ +/** @public */ export const CursorTimeoutMode = Object.freeze({ ITERATION: 'iteration', LIFETIME: 'cursorLifetime' } as const); /** @public - * TODO(NODE-5688): Document and release - * */ + * Specifies how `timeoutMS` is applied to the cursor. Can be either `'cursorLifeTime'` or `'iteration'` + * When set to `'iteration'`, the deadline specified by `timeoutMS` applies to each call of + * `cursor.next()`. + * When set to `'cursorLifetime'`, the deadline applies to the life of the entire cursor. + * + * @example + * # Example showing use of `'iteration'` + * ```ts + * const cursor = collection.find({}, {timeoutMS: 100, timeoutMode: 'iteration'}); + * for await (const doc of cursor) { + * // process doc + * // This will throw a timeout error if any of the iterator's `next()` calls takes more than 100ms, but + * will continue to iterate successfully otherwise, regardless of the number of batches. + * } + * ``` + * + * # Example showing use of `'cursorLifetime'` + * + * ```ts + * const cursor = collection.find({}, { timeoutMS: 1000, timeoutMode: 'cursorLifetime' }); + * const docs = await cursor.toArray(); // This entire line will throw a timeout error if all batches are not fetched and returned within 1000ms. + * ``` + */ export type CursorTimeoutMode = (typeof CursorTimeoutMode)[keyof typeof CursorTimeoutMode]; /** @public */ @@ -116,9 +137,32 @@ export interface AbstractCursorOptions extends BSONSerializeOptions { */ awaitData?: boolean; noCursorTimeout?: boolean; - /** @internal TODO(NODE-5688): make this public */ + /** Specifies the time an operation will run until it throws a timeout error. See {@link AbstractCursorOptions.timeoutMode} for more details. */ timeoutMS?: number; - /** @internal TODO(NODE-5688): make this public */ + /** + * Specifies how `timeoutMS` is applied to the cursor. Can be either `'cursorLifeTime'` or `'iteration'` + * When set to `'iteration'`, the deadline specified by `timeoutMS` applies to each call of + * `cursor.next()`. + * When set to `'cursorLifetime'`, the deadline applies to the life of the entire cursor. + * + * @example + * # Example showing use of `'iteration'` + * ```ts + * const cursor = collection.find({}, {timeoutMS: 100, timeoutMode: 'iteration'}); + * for await (const doc of cursor) { + * // process doc + * // This will throw a timeout error if any of the iterator's `next()` calls takes more than 100ms, but + * will continue to iterate successfully otherwise, regardless of the number of batches. + * } + * ``` + * + * # Example showing use of `'cursorLifetime'` + * + * ```ts + * const cursor = collection.find({}, { timeoutMS: 1000, timeoutMode: 'cursorLifetime' }); + * const docs = await cursor.toArray(); // This entire line will throw a timeout error if all batches are not fetched and returned within 1000ms. + * ``` + */ timeoutMode?: CursorTimeoutMode; /** diff --git a/src/db.ts b/src/db.ts index d62a719382e..02fab9b2c00 100644 --- a/src/db.ts +++ b/src/db.ts @@ -97,7 +97,7 @@ export interface DbOptions extends BSONSerializeOptions, WriteConcernOptions { readConcern?: ReadConcern; /** Should retry failed writes */ retryWrites?: boolean; - /** @internal TODO(NODE-5688): make this public */ + /** Specifies the time an operation will run until it throws a timeout error */ timeoutMS?: number; } @@ -222,7 +222,6 @@ export class Db { return this.s.namespace.toString(); } - /** @internal */ get timeoutMS(): number | undefined { return this.s.options?.timeoutMS; } diff --git a/src/error.ts b/src/error.ts index 2f59f688c92..9beda0f3664 100644 --- a/src/error.ts +++ b/src/error.ts @@ -865,7 +865,6 @@ export class MongoUnexpectedServerResponseError extends MongoRuntimeError { * @category Error * * This error is thrown when an operation could not be completed within the specified `timeoutMS`. - * TODO(NODE-5688): expand this documentation. * * @example * ```ts diff --git a/src/gridfs/index.ts b/src/gridfs/index.ts index 67df4548cb0..1d344704a8b 100644 --- a/src/gridfs/index.ts +++ b/src/gridfs/index.ts @@ -38,7 +38,7 @@ export interface GridFSBucketOptions extends WriteConcernOptions { chunkSizeBytes?: number; /** Read preference to be passed to read operations */ readPreference?: ReadPreference; - /** @internal TODO(NODE-5688): make this public */ + /** Specifies the time an operation will run until it throws a timeout error */ timeoutMS?: number; } diff --git a/src/mongo_client.ts b/src/mongo_client.ts index 1c9d7843796..99857f1b05d 100644 --- a/src/mongo_client.ts +++ b/src/mongo_client.ts @@ -130,7 +130,7 @@ export type SupportedNodeConnectionOptions = SupportedTLSConnectionOptions & export interface MongoClientOptions extends BSONSerializeOptions, SupportedNodeConnectionOptions { /** Specifies the name of the replica set, if the mongod is a member of a replica set. */ replicaSet?: string; - /** @internal TODO(NODE-5688): This option is in development and currently has no behaviour. */ + /** Specifies the time an operation will run until it throws a timeout error */ timeoutMS?: number; /** Enables or disables TLS/SSL for the connection. */ tls?: boolean; @@ -488,7 +488,6 @@ export class MongoClient extends TypedEventEmitter implements return this.s.bsonOptions; } - /** @internal */ get timeoutMS(): number | undefined { return this.s.options.timeoutMS; } @@ -1029,6 +1028,5 @@ export interface MongoOptions * TODO: NODE-5671 - remove internal flag */ mongodbLogPath?: 'stderr' | 'stdout' | MongoDBLogWritable; - /** @internal TODO(NODE-5688): make this public */ timeoutMS?: number; } diff --git a/src/operations/indexes.ts b/src/operations/indexes.ts index 220d438d834..9ba56aba621 100644 --- a/src/operations/indexes.ts +++ b/src/operations/indexes.ts @@ -361,8 +361,6 @@ export class DropIndexOperation extends CommandOperation { /** @public */ export type ListIndexesOptions = AbstractCursorOptions & { - /** @internal TODO(NODE-5688): make this public */ - timeoutMode?: CursorTimeoutMode; /** @internal */ omitMaxTimeMS?: boolean; }; diff --git a/src/operations/operation.ts b/src/operations/operation.ts index 80cb552fcb6..bc848cd2fcc 100644 --- a/src/operations/operation.ts +++ b/src/operations/operation.ts @@ -35,7 +35,7 @@ export interface OperationOptions extends BSONSerializeOptions { /** @internal Hint to `executeOperation` to omit maxTimeMS */ omitMaxTimeMS?: boolean; - /** @internal TODO(NODE-5688): make this public */ + /** Specifies the time an operation will run until it throws a timeout error */ timeoutMS?: number; } From 7c3b34ca870a0f8c18a0e2daab7022713c5a0b19 Mon Sep 17 00:00:00 2001 From: Warren James Date: Thu, 24 Oct 2024 18:07:29 -0400 Subject: [PATCH 02/10] continue adding API docs --- src/cursor/abstract_cursor.ts | 5 +++++ src/cursor/run_command_cursor.ts | 6 ++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/cursor/abstract_cursor.ts b/src/cursor/abstract_cursor.ts index dd2f4644af8..0600704de63 100644 --- a/src/cursor/abstract_cursor.ts +++ b/src/cursor/abstract_cursor.ts @@ -73,6 +73,11 @@ export const CursorTimeoutMode = Object.freeze({ * `cursor.next()`. * When set to `'cursorLifetime'`, the deadline applies to the life of the entire cursor. * + * Depending on the type of cursor being used, this option has different default values. + * For non-tailable cursors, this value defaults to `'cursorLifetime'` + * For tailable cursors, this value defaults to `'iteration'` since tailable cursors, by + * definition can have an arbitrarily long lifetime. + * * @example * # Example showing use of `'iteration'` * ```ts diff --git a/src/cursor/run_command_cursor.ts b/src/cursor/run_command_cursor.ts index 15f95042c7f..51915795c6e 100644 --- a/src/cursor/run_command_cursor.ts +++ b/src/cursor/run_command_cursor.ts @@ -19,9 +19,11 @@ import { export type RunCursorCommandOptions = { readPreference?: ReadPreferenceLike; session?: ClientSession; - /** @internal */ + /** Specifies the time an operation will run until it throws a timeout error. Note that if + * `maxTimeMS` is provided in the command in addition to setting `timeoutMS` in the options, then + * the original value of `maxTimeMS` will be overwritten. */ timeoutMS?: number; - /** @internal */ + /** See {@link CursorTimeoutMode} */ timeoutMode?: CursorTimeoutMode; tailable?: boolean; awaitData?: boolean; From ef1c739a6ee7f662c5a8527756674173c1dc1b6d Mon Sep 17 00:00:00 2001 From: Warren James Date: Thu, 24 Oct 2024 18:37:07 -0400 Subject: [PATCH 03/10] WIP API docs --- src/cursor/abstract_cursor.ts | 5 ++++- src/gridfs/index.ts | 4 +++- src/operations/operation.ts | 4 ++-- src/operations/run_command.ts | 2 +- src/sessions.ts | 6 ++++-- 5 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/cursor/abstract_cursor.ts b/src/cursor/abstract_cursor.ts index 0600704de63..3c05d1e3052 100644 --- a/src/cursor/abstract_cursor.ts +++ b/src/cursor/abstract_cursor.ts @@ -142,7 +142,7 @@ export interface AbstractCursorOptions extends BSONSerializeOptions { */ awaitData?: boolean; noCursorTimeout?: boolean; - /** Specifies the time an operation will run until it throws a timeout error. See {@link AbstractCursorOptions.timeoutMode} for more details. */ + /** Specifies the time an operation will run until it throws a timeout error. See {@link AbstractCursorOptions.timeoutMode} for more details on how this option applies to cursors. */ timeoutMS?: number; /** * Specifies how `timeoutMS` is applied to the cursor. Can be either `'cursorLifeTime'` or `'iteration'` @@ -150,6 +150,9 @@ export interface AbstractCursorOptions extends BSONSerializeOptions { * `cursor.next()`. * When set to `'cursorLifetime'`, the deadline applies to the life of the entire cursor. * + * Note that the use of '`cursorLifetime`' should be limited to relatively short-lived cursors as + * it has the potential to hang on an operation for the entirety of `timeoutMS`. + * * @example * # Example showing use of `'iteration'` * ```ts diff --git a/src/gridfs/index.ts b/src/gridfs/index.ts index 1d344704a8b..6a853867775 100644 --- a/src/gridfs/index.ts +++ b/src/gridfs/index.ts @@ -38,7 +38,9 @@ export interface GridFSBucketOptions extends WriteConcernOptions { chunkSizeBytes?: number; /** Read preference to be passed to read operations */ readPreference?: ReadPreference; - /** Specifies the time an operation will run until it throws a timeout error */ + /** Specifies the time an operation will run until it throws a timeout error. Note that the + * deadline specified by this option may be breached if calls to interact with the stream take + * longer than the remaining timeout. FIXME(NODE-6456): what does this even mean?*/ timeoutMS?: number; } diff --git a/src/operations/operation.ts b/src/operations/operation.ts index bc848cd2fcc..f92c1f6192e 100644 --- a/src/operations/operation.ts +++ b/src/operations/operation.ts @@ -61,9 +61,9 @@ export abstract class AbstractOperation { options: OperationOptions; - /** @internal */ + /** @internal TODO(NODE-6197): remove dead code */ timeout?: Timeout; - /** @internal */ + /** Specifies the time an operation will run until it throws a timeout error.*/ timeoutMS?: number; [kSession]: ClientSession | undefined; diff --git a/src/operations/run_command.ts b/src/operations/run_command.ts index 1747f10c8be..9422de22165 100644 --- a/src/operations/run_command.ts +++ b/src/operations/run_command.ts @@ -15,7 +15,7 @@ export type RunCommandOptions = { session?: ClientSession; /** The read preference */ readPreference?: ReadPreferenceLike; - /** @internal */ + /** Specifies the time an operation will run until it throws a timeout error */ timeoutMS?: number; /** @internal */ omitMaxTimeMS?: boolean; diff --git a/src/sessions.ts b/src/sessions.ts index 9ada6124d5a..55b0a2fab1b 100644 --- a/src/sessions.ts +++ b/src/sessions.ts @@ -103,7 +103,7 @@ export interface EndSessionOptions { force?: boolean; forceClear?: boolean; - /** @internal */ + /** Specifies the time an operation will run until it throws a timeout error */ timeoutMS?: number; } @@ -145,7 +145,7 @@ export class ClientSession [kPinnedConnection]?: Connection; /** @internal */ [kTxnNumberIncrement]: number; - /** @internal */ + /** Specifies the time an operation in a given `ClientSession` will run until it throws a timeout error */ timeoutMS?: number; /** @internal */ @@ -709,6 +709,8 @@ export class ClientSession * **IMPORTANT:** Running operations in parallel is not supported during a transaction. The use of `Promise.all`, * `Promise.allSettled`, `Promise.race`, etc to parallelize operations inside a transaction is * undefined behaviour. + * + * **IMPORTANT:** When running a * * * @remarks From 306a9554ecae19dc4195d3457153623654d786f4 Mon Sep 17 00:00:00 2001 From: Warren James Date: Thu, 24 Oct 2024 18:37:14 -0400 Subject: [PATCH 04/10] lint --- src/sessions.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sessions.ts b/src/sessions.ts index 55b0a2fab1b..edd8e1495e9 100644 --- a/src/sessions.ts +++ b/src/sessions.ts @@ -709,8 +709,8 @@ export class ClientSession * **IMPORTANT:** Running operations in parallel is not supported during a transaction. The use of `Promise.all`, * `Promise.allSettled`, `Promise.race`, etc to parallelize operations inside a transaction is * undefined behaviour. - * - * **IMPORTANT:** When running a + * + * **IMPORTANT:** When running a * * * @remarks From ee2c37f8e7ec3349ae767c459e8158929be3cf74 Mon Sep 17 00:00:00 2001 From: Warren James Date: Mon, 28 Oct 2024 13:23:11 -0400 Subject: [PATCH 05/10] update docs --- src/cursor/run_command_cursor.ts | 30 +++++++++++++++++++++++++++++- src/gridfs/index.ts | 5 ++--- src/operations/indexes.ts | 2 +- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/cursor/run_command_cursor.ts b/src/cursor/run_command_cursor.ts index 51915795c6e..3cd4014a08a 100644 --- a/src/cursor/run_command_cursor.ts +++ b/src/cursor/run_command_cursor.ts @@ -23,7 +23,35 @@ export type RunCursorCommandOptions = { * `maxTimeMS` is provided in the command in addition to setting `timeoutMS` in the options, then * the original value of `maxTimeMS` will be overwritten. */ timeoutMS?: number; - /** See {@link CursorTimeoutMode} */ + /** @public + * Specifies how `timeoutMS` is applied to the cursor. Can be either `'cursorLifeTime'` or `'iteration'` + * When set to `'iteration'`, the deadline specified by `timeoutMS` applies to each call of + * `cursor.next()`. + * When set to `'cursorLifetime'`, the deadline applies to the life of the entire cursor. + * + * Depending on the type of cursor being used, this option has different default values. + * For non-tailable cursors, this value defaults to `'cursorLifetime'` + * For tailable cursors, this value defaults to `'iteration'` since tailable cursors, by + * definition can have an arbitrarily long lifetime. + * + * @example + * # Example showing use of `'iteration'` + * ```ts + * const cursor = collection.find({}, {timeoutMS: 100, timeoutMode: 'iteration'}); + * for await (const doc of cursor) { + * // process doc + * // This will throw a timeout error if any of the iterator's `next()` calls takes more than 100ms, but + * will continue to iterate successfully otherwise, regardless of the number of batches. + * } + * ``` + * + * # Example showing use of `'cursorLifetime'` + * + * ```ts + * const cursor = collection.find({}, { timeoutMS: 1000, timeoutMode: 'cursorLifetime' }); + * const docs = await cursor.toArray(); // This entire line will throw a timeout error if all batches are not fetched and returned within 1000ms. + * ``` + */ timeoutMode?: CursorTimeoutMode; tailable?: boolean; awaitData?: boolean; diff --git a/src/gridfs/index.ts b/src/gridfs/index.ts index 6a853867775..648fdac9832 100644 --- a/src/gridfs/index.ts +++ b/src/gridfs/index.ts @@ -38,9 +38,8 @@ export interface GridFSBucketOptions extends WriteConcernOptions { chunkSizeBytes?: number; /** Read preference to be passed to read operations */ readPreference?: ReadPreference; - /** Specifies the time an operation will run until it throws a timeout error. Note that the - * deadline specified by this option may be breached if calls to interact with the stream take - * longer than the remaining timeout. FIXME(NODE-6456): what does this even mean?*/ + /** Specifies the lifetime duration of a gridFS stream. If any async operations are in progress + * when this timeout expires, the stream will throw a timeout error. */ timeoutMS?: number; } diff --git a/src/operations/indexes.ts b/src/operations/indexes.ts index 9ba56aba621..afd05f5be36 100644 --- a/src/operations/indexes.ts +++ b/src/operations/indexes.ts @@ -1,7 +1,7 @@ import type { Document } from '../bson'; import { CursorResponse } from '../cmap/wire_protocol/responses'; import type { Collection } from '../collection'; -import { type AbstractCursorOptions, type CursorTimeoutMode } from '../cursor/abstract_cursor'; +import { type AbstractCursorOptions } from '../cursor/abstract_cursor'; import { MongoCompatibilityError } from '../error'; import { type OneOrMore } from '../mongo_types'; import type { Server } from '../sdam/server'; From f0243cb44553ffdc63b50dce859c9d531e004312 Mon Sep 17 00:00:00 2001 From: Warren James Date: Mon, 28 Oct 2024 15:53:35 -0400 Subject: [PATCH 06/10] update sessions docs --- src/sessions.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sessions.ts b/src/sessions.ts index edd8e1495e9..cd8f71d5186 100644 --- a/src/sessions.ts +++ b/src/sessions.ts @@ -710,7 +710,8 @@ export class ClientSession * `Promise.allSettled`, `Promise.race`, etc to parallelize operations inside a transaction is * undefined behaviour. * - * **IMPORTANT:** When running a + * **IMPORTANT:** When running an operation inside a `withTransaction` callback, if it is not + * provided the explicit session in its options, it will not respect the timeoutMS. * * * @remarks From 14abcb22bcd786af373311f9f25fced7e0da49da Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Thu, 31 Oct 2024 09:30:05 -0400 Subject: [PATCH 07/10] docs: fix fmt, export enum --- src/collection.ts | 2 +- src/cursor/abstract_cursor.ts | 25 +++++++------- src/cursor/run_command_cursor.ts | 13 +++---- src/gridfs/index.ts | 6 ++-- src/index.ts | 8 +++-- src/operations/operation.ts | 4 +-- src/sessions.ts | 2 +- .../node_csot.test.ts | 3 +- test/unit/index.test.ts | 34 ++++++------------- 9 files changed, 45 insertions(+), 52 deletions(-) diff --git a/src/collection.ts b/src/collection.ts index 9ce5049efe8..7229c064bbf 100644 --- a/src/collection.ts +++ b/src/collection.ts @@ -262,7 +262,7 @@ export class Collection { this.s.collectionHint = normalizeHintField(v); } - get timeoutMS(): number | undefined { + public get timeoutMS(): number | undefined { return this.s.options.timeoutMS; } diff --git a/src/cursor/abstract_cursor.ts b/src/cursor/abstract_cursor.ts index 3c05d1e3052..881873808ec 100644 --- a/src/cursor/abstract_cursor.ts +++ b/src/cursor/abstract_cursor.ts @@ -61,13 +61,8 @@ export interface CursorStreamOptions { /** @public */ export type CursorFlag = (typeof CURSOR_FLAGS)[number]; -/** @public */ -export const CursorTimeoutMode = Object.freeze({ - ITERATION: 'iteration', - LIFETIME: 'cursorLifetime' -} as const); - -/** @public +/** + * @public * Specifies how `timeoutMS` is applied to the cursor. Can be either `'cursorLifeTime'` or `'iteration'` * When set to `'iteration'`, the deadline specified by `timeoutMS` applies to each call of * `cursor.next()`. @@ -85,7 +80,7 @@ export const CursorTimeoutMode = Object.freeze({ * for await (const doc of cursor) { * // process doc * // This will throw a timeout error if any of the iterator's `next()` calls takes more than 100ms, but - * will continue to iterate successfully otherwise, regardless of the number of batches. + * // will continue to iterate successfully otherwise, regardless of the number of batches. * } * ``` * @@ -96,6 +91,12 @@ export const CursorTimeoutMode = Object.freeze({ * const docs = await cursor.toArray(); // This entire line will throw a timeout error if all batches are not fetched and returned within 1000ms. * ``` */ +export const CursorTimeoutMode = Object.freeze({ + ITERATION: 'iteration', + LIFETIME: 'cursorLifetime' +} as const); + +/** @public */ export type CursorTimeoutMode = (typeof CursorTimeoutMode)[keyof typeof CursorTimeoutMode]; /** @public */ @@ -154,21 +155,19 @@ export interface AbstractCursorOptions extends BSONSerializeOptions { * it has the potential to hang on an operation for the entirety of `timeoutMS`. * * @example - * # Example showing use of `'iteration'` * ```ts * const cursor = collection.find({}, {timeoutMS: 100, timeoutMode: 'iteration'}); * for await (const doc of cursor) { * // process doc * // This will throw a timeout error if any of the iterator's `next()` calls takes more than 100ms, but - * will continue to iterate successfully otherwise, regardless of the number of batches. + * // will continue to iterate successfully otherwise, regardless of the number of batches. * } * ``` * - * # Example showing use of `'cursorLifetime'` - * + * @example * ```ts * const cursor = collection.find({}, { timeoutMS: 1000, timeoutMode: 'cursorLifetime' }); - * const docs = await cursor.toArray(); // This entire line will throw a timeout error if all batches are not fetched and returned within 1000ms. + * const docs = await cursor.toArray(); // This line will throw a timeout error if all batches are not fetched and returned within 1000ms. * ``` */ timeoutMode?: CursorTimeoutMode; diff --git a/src/cursor/run_command_cursor.ts b/src/cursor/run_command_cursor.ts index 3cd4014a08a..ad8d5c338b3 100644 --- a/src/cursor/run_command_cursor.ts +++ b/src/cursor/run_command_cursor.ts @@ -19,11 +19,14 @@ import { export type RunCursorCommandOptions = { readPreference?: ReadPreferenceLike; session?: ClientSession; - /** Specifies the time an operation will run until it throws a timeout error. Note that if + /** + * Specifies the time an operation will run until it throws a timeout error. Note that if * `maxTimeMS` is provided in the command in addition to setting `timeoutMS` in the options, then - * the original value of `maxTimeMS` will be overwritten. */ + * the original value of `maxTimeMS` will be overwritten. + */ timeoutMS?: number; - /** @public + /** + * @public * Specifies how `timeoutMS` is applied to the cursor. Can be either `'cursorLifeTime'` or `'iteration'` * When set to `'iteration'`, the deadline specified by `timeoutMS` applies to each call of * `cursor.next()`. @@ -35,7 +38,6 @@ export type RunCursorCommandOptions = { * definition can have an arbitrarily long lifetime. * * @example - * # Example showing use of `'iteration'` * ```ts * const cursor = collection.find({}, {timeoutMS: 100, timeoutMode: 'iteration'}); * for await (const doc of cursor) { @@ -45,8 +47,7 @@ export type RunCursorCommandOptions = { * } * ``` * - * # Example showing use of `'cursorLifetime'` - * + * @example * ```ts * const cursor = collection.find({}, { timeoutMS: 1000, timeoutMode: 'cursorLifetime' }); * const docs = await cursor.toArray(); // This entire line will throw a timeout error if all batches are not fetched and returned within 1000ms. diff --git a/src/gridfs/index.ts b/src/gridfs/index.ts index 648fdac9832..a057febaea4 100644 --- a/src/gridfs/index.ts +++ b/src/gridfs/index.ts @@ -38,8 +38,10 @@ export interface GridFSBucketOptions extends WriteConcernOptions { chunkSizeBytes?: number; /** Read preference to be passed to read operations */ readPreference?: ReadPreference; - /** Specifies the lifetime duration of a gridFS stream. If any async operations are in progress - * when this timeout expires, the stream will throw a timeout error. */ + /** + * Specifies the lifetime duration of a gridFS stream. If any async operations are in progress + * when this timeout expires, the stream will throw a timeout error. + */ timeoutMS?: number; } diff --git a/src/index.ts b/src/index.ts index 65f9ec7ccb7..dd4d8a21d95 100644 --- a/src/index.ts +++ b/src/index.ts @@ -37,7 +37,11 @@ export { Timestamp, UUID } from './bson'; -export { AnyBulkWriteOperation, BulkWriteOptions, MongoBulkWriteError } from './bulk/common'; +export { + type AnyBulkWriteOperation, + type BulkWriteOptions, + MongoBulkWriteError +} from './bulk/common'; export { ClientEncryption } from './client-side-encryption/client_encryption'; export { ChangeStreamCursor } from './cursor/change_stream_cursor'; export { @@ -111,7 +115,7 @@ export { AutoEncryptionLoggerLevel } from './client-side-encryption/auto_encrypt export { GSSAPICanonicalizationValue } from './cmap/auth/gssapi'; export { AuthMechanism } from './cmap/auth/providers'; export { Compressor } from './cmap/wire_protocol/compression'; -export { CURSOR_FLAGS, type CursorTimeoutMode } from './cursor/abstract_cursor'; +export { CURSOR_FLAGS, CursorTimeoutMode } from './cursor/abstract_cursor'; export { MongoErrorLabel } from './error'; export { ExplainVerbosity } from './explain'; export { ServerApiVersion } from './mongo_client'; diff --git a/src/operations/operation.ts b/src/operations/operation.ts index f92c1f6192e..95b00647bb5 100644 --- a/src/operations/operation.ts +++ b/src/operations/operation.ts @@ -61,9 +61,9 @@ export abstract class AbstractOperation { options: OperationOptions; - /** @internal TODO(NODE-6197): remove dead code */ + /** TODO(NODE-6197): remove dead code */ timeout?: Timeout; - /** Specifies the time an operation will run until it throws a timeout error.*/ + /** Specifies the time an operation will run until it throws a timeout error. */ timeoutMS?: number; [kSession]: ClientSession | undefined; diff --git a/src/sessions.ts b/src/sessions.ts index cd8f71d5186..68700eb6d0b 100644 --- a/src/sessions.ts +++ b/src/sessions.ts @@ -711,7 +711,7 @@ export class ClientSession * undefined behaviour. * * **IMPORTANT:** When running an operation inside a `withTransaction` callback, if it is not - * provided the explicit session in its options, it will not respect the timeoutMS. + * provided the explicit session in its options, it will not be part of the transaction and it will not respect timeoutMS. * * * @remarks diff --git a/test/integration/client-side-operations-timeout/node_csot.test.ts b/test/integration/client-side-operations-timeout/node_csot.test.ts index b63ffa8da22..ec69dcc1b7b 100644 --- a/test/integration/client-side-operations-timeout/node_csot.test.ts +++ b/test/integration/client-side-operations-timeout/node_csot.test.ts @@ -18,6 +18,7 @@ import { type CommandStartedEvent, type CommandSucceededEvent, Connection, + CursorTimeoutMode, type Db, type FindCursor, GridFSBucket, @@ -423,7 +424,7 @@ describe('CSOT driver tests', metadata, () => { const cursor = client .db('db') .collection('coll') - .find({}, { batchSize: 3, timeoutMode: 'iteration', timeoutMS: 10 }) + .find({}, { batchSize: 3, timeoutMode: CursorTimeoutMode.ITERATION, timeoutMS: 10 }) .limit(3); const maybeError = await cursor.next().then( diff --git a/test/unit/index.test.ts b/test/unit/index.test.ts index a76aff98d91..7b064b1078d 100644 --- a/test/unit/index.test.ts +++ b/test/unit/index.test.ts @@ -5,14 +5,7 @@ import { expect } from 'chai'; import * as mongodb from '../../src/index'; import { setDifference } from '../mongodb'; -/** - * TS-NODE Adds these keys but they are undefined, they are not present when you import from lib - * We did not think this strangeness was worth investigating so we just make sure they remain set to undefined - */ -const TS_NODE_EXPORTS = ['AnyBulkWriteOperation', 'BulkWriteOptions']; - const EXPECTED_EXPORTS = [ - ...TS_NODE_EXPORTS, 'AbstractCursor', 'Admin', 'AggregationCursor', @@ -31,11 +24,11 @@ const EXPECTED_EXPORTS = [ 'ClientSession', 'Code', 'Collection', - 'configureExplicitResourceManagement', 'CommandFailedEvent', 'CommandStartedEvent', 'CommandSucceededEvent', 'Compressor', + 'configureExplicitResourceManagement', 'ConnectionCheckedInEvent', 'ConnectionCheckedOutEvent', 'ConnectionCheckOutFailedEvent', @@ -49,12 +42,13 @@ const EXPECTED_EXPORTS = [ 'ConnectionPoolReadyEvent', 'ConnectionReadyEvent', 'CURSOR_FLAGS', + 'CursorTimeoutMode', 'Db', 'DBRef', 'Decimal128', 'Double', - 'ExplainVerbosity', 'ExplainableCursor', + 'ExplainVerbosity', 'FindCursor', 'GridFSBucket', 'GridFSBucketReadStream', @@ -102,6 +96,7 @@ const EXPECTED_EXPORTS = [ 'MongoNetworkTimeoutError', 'MongoNotConnectedError', 'MongoOIDCError', + 'MongoOperationTimeoutError', 'MongoParseError', 'MongoRuntimeError', 'MongoServerClosedError', @@ -111,10 +106,8 @@ const EXPECTED_EXPORTS = [ 'MongoTailableCursorError', 'MongoTopologyClosedError', 'MongoTransactionError', - 'MongoOperationTimeoutError', 'MongoUnexpectedServerResponseError', 'MongoWriteConcernError', - 'WriteConcernErrorResult', 'ObjectId', 'OrderedBulkOperation', 'ProfilingLevel', @@ -130,6 +123,10 @@ const EXPECTED_EXPORTS = [ 'ServerHeartbeatStartedEvent', 'ServerHeartbeatSucceededEvent', 'ServerOpeningEvent', + 'ServerSelectionEvent', + 'ServerSelectionFailedEvent', + 'ServerSelectionStartedEvent', + 'ServerSelectionSucceededEvent', 'ServerType', 'SrvPollingEvent', 'Timestamp', @@ -139,12 +136,9 @@ const EXPECTED_EXPORTS = [ 'TopologyType', 'UnorderedBulkOperation', 'UUID', + 'WaitingForSuitableServerEvent', 'WriteConcern', - 'ServerSelectionEvent', - 'ServerSelectionFailedEvent', - 'ServerSelectionStartedEvent', - 'ServerSelectionSucceededEvent', - 'WaitingForSuitableServerEvent' + 'WriteConcernErrorResult' ]; describe('mongodb entrypoint', () => { @@ -155,12 +149,4 @@ describe('mongodb entrypoint', () => { it('exports only the expected keys', () => { expect(setDifference(Object.keys(mongodb), EXPECTED_EXPORTS)).to.be.empty; }); - - it('should export keys added by ts-node as undefined', () => { - // If the array is empty, this test would be a no-op so we should remove it - expect(TS_NODE_EXPORTS).to.have.length.greaterThan(0); - for (const tsNodeExportKey of TS_NODE_EXPORTS) { - expect(mongodb).to.have.property(tsNodeExportKey, undefined); - } - }); }); From a35fa910053a992c74b222a91da044261b439e23 Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Fri, 1 Nov 2024 11:11:15 -0400 Subject: [PATCH 08/10] chore: fixes --- src/cursor/abstract_cursor.ts | 15 +++++++++------ src/cursor/run_command_cursor.ts | 3 ++- src/db.ts | 2 +- src/operations/operation.ts | 2 -- 4 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/cursor/abstract_cursor.ts b/src/cursor/abstract_cursor.ts index 881873808ec..09d9eb02b8d 100644 --- a/src/cursor/abstract_cursor.ts +++ b/src/cursor/abstract_cursor.ts @@ -63,6 +63,7 @@ export type CursorFlag = (typeof CURSOR_FLAGS)[number]; /** * @public + * @experimental * Specifies how `timeoutMS` is applied to the cursor. Can be either `'cursorLifeTime'` or `'iteration'` * When set to `'iteration'`, the deadline specified by `timeoutMS` applies to each call of * `cursor.next()`. @@ -74,7 +75,6 @@ export type CursorFlag = (typeof CURSOR_FLAGS)[number]; * definition can have an arbitrarily long lifetime. * * @example - * # Example showing use of `'iteration'` * ```ts * const cursor = collection.find({}, {timeoutMS: 100, timeoutMode: 'iteration'}); * for await (const doc of cursor) { @@ -84,8 +84,7 @@ export type CursorFlag = (typeof CURSOR_FLAGS)[number]; * } * ``` * - * # Example showing use of `'cursorLifetime'` - * + * @example * ```ts * const cursor = collection.find({}, { timeoutMS: 1000, timeoutMode: 'cursorLifetime' }); * const docs = await cursor.toArray(); // This entire line will throw a timeout error if all batches are not fetched and returned within 1000ms. @@ -146,13 +145,17 @@ export interface AbstractCursorOptions extends BSONSerializeOptions { /** Specifies the time an operation will run until it throws a timeout error. See {@link AbstractCursorOptions.timeoutMode} for more details on how this option applies to cursors. */ timeoutMS?: number; /** + * @public + * @experimental * Specifies how `timeoutMS` is applied to the cursor. Can be either `'cursorLifeTime'` or `'iteration'` * When set to `'iteration'`, the deadline specified by `timeoutMS` applies to each call of * `cursor.next()`. * When set to `'cursorLifetime'`, the deadline applies to the life of the entire cursor. * - * Note that the use of '`cursorLifetime`' should be limited to relatively short-lived cursors as - * it has the potential to hang on an operation for the entirety of `timeoutMS`. + * Depending on the type of cursor being used, this option has different default values. + * For non-tailable cursors, this value defaults to `'cursorLifetime'` + * For tailable cursors, this value defaults to `'iteration'` since tailable cursors, by + * definition can have an arbitrarily long lifetime. * * @example * ```ts @@ -167,7 +170,7 @@ export interface AbstractCursorOptions extends BSONSerializeOptions { * @example * ```ts * const cursor = collection.find({}, { timeoutMS: 1000, timeoutMode: 'cursorLifetime' }); - * const docs = await cursor.toArray(); // This line will throw a timeout error if all batches are not fetched and returned within 1000ms. + * const docs = await cursor.toArray(); // This entire line will throw a timeout error if all batches are not fetched and returned within 1000ms. * ``` */ timeoutMode?: CursorTimeoutMode; diff --git a/src/cursor/run_command_cursor.ts b/src/cursor/run_command_cursor.ts index ad8d5c338b3..0f252c43c1d 100644 --- a/src/cursor/run_command_cursor.ts +++ b/src/cursor/run_command_cursor.ts @@ -27,6 +27,7 @@ export type RunCursorCommandOptions = { timeoutMS?: number; /** * @public + * @experimental * Specifies how `timeoutMS` is applied to the cursor. Can be either `'cursorLifeTime'` or `'iteration'` * When set to `'iteration'`, the deadline specified by `timeoutMS` applies to each call of * `cursor.next()`. @@ -43,7 +44,7 @@ export type RunCursorCommandOptions = { * for await (const doc of cursor) { * // process doc * // This will throw a timeout error if any of the iterator's `next()` calls takes more than 100ms, but - * will continue to iterate successfully otherwise, regardless of the number of batches. + * // will continue to iterate successfully otherwise, regardless of the number of batches. * } * ``` * diff --git a/src/db.ts b/src/db.ts index 02fab9b2c00..91ab3d5f8fd 100644 --- a/src/db.ts +++ b/src/db.ts @@ -222,7 +222,7 @@ export class Db { return this.s.namespace.toString(); } - get timeoutMS(): number | undefined { + public get timeoutMS(): number | undefined { return this.s.options?.timeoutMS; } diff --git a/src/operations/operation.ts b/src/operations/operation.ts index 95b00647bb5..25195af4d35 100644 --- a/src/operations/operation.ts +++ b/src/operations/operation.ts @@ -61,8 +61,6 @@ export abstract class AbstractOperation { options: OperationOptions; - /** TODO(NODE-6197): remove dead code */ - timeout?: Timeout; /** Specifies the time an operation will run until it throws a timeout error. */ timeoutMS?: number; From 609708700cbdcb80d57c432d6567ef19320d73ec Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Fri, 1 Nov 2024 13:30:55 -0400 Subject: [PATCH 09/10] chore: comments --- src/collection.ts | 5 ++++- src/cursor/abstract_cursor.ts | 5 ++++- src/db.ts | 5 ++++- src/gridfs/index.ts | 1 + src/mongo_client.ts | 5 ++++- src/operations/operation.ts | 7 +++++-- src/operations/run_command.ts | 5 ++++- src/sessions.ts | 5 ++++- 8 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/collection.ts b/src/collection.ts index 7229c064bbf..24469b56efa 100644 --- a/src/collection.ts +++ b/src/collection.ts @@ -115,7 +115,10 @@ export interface CollectionOptions extends BSONSerializeOptions, WriteConcernOpt readConcern?: ReadConcernLike; /** The preferred read preference (ReadPreference.PRIMARY, ReadPreference.PRIMARY_PREFERRED, ReadPreference.SECONDARY, ReadPreference.SECONDARY_PREFERRED, ReadPreference.NEAREST). */ readPreference?: ReadPreferenceLike; - /** Specifies the time an operation will run until it throws a timeout error */ + /** + * @experimental + * Specifies the time an operation will run until it throws a timeout error + */ timeoutMS?: number; } diff --git a/src/cursor/abstract_cursor.ts b/src/cursor/abstract_cursor.ts index 09d9eb02b8d..ab052dd11b2 100644 --- a/src/cursor/abstract_cursor.ts +++ b/src/cursor/abstract_cursor.ts @@ -95,7 +95,10 @@ export const CursorTimeoutMode = Object.freeze({ LIFETIME: 'cursorLifetime' } as const); -/** @public */ +/** + * @public + * @experimental + */ export type CursorTimeoutMode = (typeof CursorTimeoutMode)[keyof typeof CursorTimeoutMode]; /** @public */ diff --git a/src/db.ts b/src/db.ts index 91ab3d5f8fd..121d6fc4f1e 100644 --- a/src/db.ts +++ b/src/db.ts @@ -97,7 +97,10 @@ export interface DbOptions extends BSONSerializeOptions, WriteConcernOptions { readConcern?: ReadConcern; /** Should retry failed writes */ retryWrites?: boolean; - /** Specifies the time an operation will run until it throws a timeout error */ + /** + * @experimental + * Specifies the time an operation will run until it throws a timeout error + */ timeoutMS?: number; } diff --git a/src/gridfs/index.ts b/src/gridfs/index.ts index a057febaea4..70f154431cf 100644 --- a/src/gridfs/index.ts +++ b/src/gridfs/index.ts @@ -39,6 +39,7 @@ export interface GridFSBucketOptions extends WriteConcernOptions { /** Read preference to be passed to read operations */ readPreference?: ReadPreference; /** + * @experimental * Specifies the lifetime duration of a gridFS stream. If any async operations are in progress * when this timeout expires, the stream will throw a timeout error. */ diff --git a/src/mongo_client.ts b/src/mongo_client.ts index 99857f1b05d..f16d165a236 100644 --- a/src/mongo_client.ts +++ b/src/mongo_client.ts @@ -130,7 +130,10 @@ export type SupportedNodeConnectionOptions = SupportedTLSConnectionOptions & export interface MongoClientOptions extends BSONSerializeOptions, SupportedNodeConnectionOptions { /** Specifies the name of the replica set, if the mongod is a member of a replica set. */ replicaSet?: string; - /** Specifies the time an operation will run until it throws a timeout error */ + /** + * @experimental + * Specifies the time an operation will run until it throws a timeout error + */ timeoutMS?: number; /** Enables or disables TLS/SSL for the connection. */ tls?: boolean; diff --git a/src/operations/operation.ts b/src/operations/operation.ts index 25195af4d35..1c5be203516 100644 --- a/src/operations/operation.ts +++ b/src/operations/operation.ts @@ -2,7 +2,7 @@ import { type BSONSerializeOptions, type Document, resolveBSONOptions } from '.. import { ReadPreference, type ReadPreferenceLike } from '../read_preference'; import type { Server } from '../sdam/server'; import type { ClientSession } from '../sessions'; -import { type Timeout, type TimeoutContext } from '../timeout'; +import { type TimeoutContext } from '../timeout'; import type { MongoDBNamespace } from '../utils'; export const Aspect = { @@ -35,7 +35,10 @@ export interface OperationOptions extends BSONSerializeOptions { /** @internal Hint to `executeOperation` to omit maxTimeMS */ omitMaxTimeMS?: boolean; - /** Specifies the time an operation will run until it throws a timeout error */ + /** + * @experimental + * Specifies the time an operation will run until it throws a timeout error + */ timeoutMS?: number; } diff --git a/src/operations/run_command.ts b/src/operations/run_command.ts index 9422de22165..db5c5a7c169 100644 --- a/src/operations/run_command.ts +++ b/src/operations/run_command.ts @@ -15,7 +15,10 @@ export type RunCommandOptions = { session?: ClientSession; /** The read preference */ readPreference?: ReadPreferenceLike; - /** Specifies the time an operation will run until it throws a timeout error */ + /** + * @experimental + * Specifies the time an operation will run until it throws a timeout error + */ timeoutMS?: number; /** @internal */ omitMaxTimeMS?: boolean; diff --git a/src/sessions.ts b/src/sessions.ts index 68700eb6d0b..f323d1a93be 100644 --- a/src/sessions.ts +++ b/src/sessions.ts @@ -145,7 +145,10 @@ export class ClientSession [kPinnedConnection]?: Connection; /** @internal */ [kTxnNumberIncrement]: number; - /** Specifies the time an operation in a given `ClientSession` will run until it throws a timeout error */ + /** + * @experimental + * Specifies the time an operation in a given `ClientSession` will run until it throws a timeout error + */ timeoutMS?: number; /** @internal */ From 29075b74eefc05328c5953e550e557ba98111ff0 Mon Sep 17 00:00:00 2001 From: Neal Beeken Date: Fri, 1 Nov 2024 13:31:56 -0400 Subject: [PATCH 10/10] chore: one more tag --- src/cursor/run_command_cursor.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/cursor/run_command_cursor.ts b/src/cursor/run_command_cursor.ts index 0f252c43c1d..3f6dd6d34e0 100644 --- a/src/cursor/run_command_cursor.ts +++ b/src/cursor/run_command_cursor.ts @@ -20,6 +20,7 @@ export type RunCursorCommandOptions = { readPreference?: ReadPreferenceLike; session?: ClientSession; /** + * @experimental * Specifies the time an operation will run until it throws a timeout error. Note that if * `maxTimeMS` is provided in the command in addition to setting `timeoutMS` in the options, then * the original value of `maxTimeMS` will be overwritten.