Skip to content

docs(NODE-6456): document CSOT pt 1 #4292

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

Merged
merged 11 commits into from
Nov 1, 2024
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
8 changes: 5 additions & 3 deletions src/collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
/** @internal TODO(NODE-5688): make this public */
/**
* @experimental
* Specifies the time an operation will run until it throws a timeout error
*/
timeoutMS?: number;
}

Expand Down Expand Up @@ -262,8 +265,7 @@ export class Collection<TSchema extends Document = Document> {
this.s.collectionHint = normalizeHintField(v);
}

/** @internal */
get timeoutMS(): number | undefined {
public get timeoutMS(): number | undefined {
return this.s.options.timeoutMS;
}

Expand Down
69 changes: 63 additions & 6 deletions src/cursor/abstract_cursor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,44 @@ export interface CursorStreamOptions {
/** @public */
export type CursorFlag = (typeof CURSOR_FLAGS)[number];

/** @public*/
/**
* @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.
*
* 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
* 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
* ```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 const CursorTimeoutMode = Object.freeze({
ITERATION: 'iteration',
LIFETIME: 'cursorLifetime'
} as const);

/** @public
* TODO(NODE-5688): Document and release
* */
/**
* @public
* @experimental
*/
export type CursorTimeoutMode = (typeof CursorTimeoutMode)[keyof typeof CursorTimeoutMode];

/** @public */
Expand Down Expand Up @@ -116,9 +145,37 @@ 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 on how this option applies to cursors. */
timeoutMS?: number;
/** @internal TODO(NODE-5688): make this public */
/**
* @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.
*
* 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
* 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
* ```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;

/**
Expand Down
37 changes: 35 additions & 2 deletions src/cursor/run_command_cursor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,42 @@ import {
export type RunCursorCommandOptions = {
readPreference?: ReadPreferenceLike;
session?: ClientSession;
/** @internal */
/**
* @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.
*/
timeoutMS?: number;
/** @internal */
/**
* @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.
*
* 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
* 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
* ```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;
Expand Down
8 changes: 5 additions & 3 deletions src/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,10 @@ export interface DbOptions extends BSONSerializeOptions, WriteConcernOptions {
readConcern?: ReadConcern;
/** Should retry failed writes */
retryWrites?: boolean;
/** @internal TODO(NODE-5688): make this public */
/**
* @experimental
* Specifies the time an operation will run until it throws a timeout error
*/
timeoutMS?: number;
}

Expand Down Expand Up @@ -222,8 +225,7 @@ export class Db {
return this.s.namespace.toString();
}

/** @internal */
get timeoutMS(): number | undefined {
public get timeoutMS(): number | undefined {
return this.s.options?.timeoutMS;
}

Expand Down
1 change: 0 additions & 1 deletion src/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
6 changes: 5 additions & 1 deletion src/gridfs/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ export interface GridFSBucketOptions extends WriteConcernOptions {
chunkSizeBytes?: number;
/** Read preference to be passed to read operations */
readPreference?: ReadPreference;
/** @internal TODO(NODE-5688): make this public */
/**
* @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.
*/
timeoutMS?: number;
}

Expand Down
8 changes: 6 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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';
Expand Down
7 changes: 4 additions & 3 deletions src/mongo_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
/** @internal TODO(NODE-5688): This option is in development and currently has no behaviour. */
/**
* @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;
Expand Down Expand Up @@ -488,7 +491,6 @@ export class MongoClient extends TypedEventEmitter<MongoClientEvents> implements
return this.s.bsonOptions;
}

/** @internal */
get timeoutMS(): number | undefined {
return this.s.options.timeoutMS;
}
Expand Down Expand Up @@ -1029,6 +1031,5 @@ export interface MongoOptions
* TODO: NODE-5671 - remove internal flag
*/
mongodbLogPath?: 'stderr' | 'stdout' | MongoDBLogWritable;
/** @internal TODO(NODE-5688): make this public */
timeoutMS?: number;
}
4 changes: 1 addition & 3 deletions src/operations/indexes.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -361,8 +361,6 @@ export class DropIndexOperation extends CommandOperation<Document> {

/** @public */
export type ListIndexesOptions = AbstractCursorOptions & {
/** @internal TODO(NODE-5688): make this public */
timeoutMode?: CursorTimeoutMode;
/** @internal */
omitMaxTimeMS?: boolean;
};
Expand Down
11 changes: 6 additions & 5 deletions src/operations/operation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -35,7 +35,10 @@ export interface OperationOptions extends BSONSerializeOptions {
/** @internal Hint to `executeOperation` to omit maxTimeMS */
omitMaxTimeMS?: boolean;

/** @internal TODO(NODE-5688): make this public */
/**
* @experimental
* Specifies the time an operation will run until it throws a timeout error
*/
timeoutMS?: number;
}

Expand All @@ -61,9 +64,7 @@ export abstract class AbstractOperation<TResult = any> {

options: OperationOptions;

/** @internal */
timeout?: Timeout;
/** @internal */
/** Specifies the time an operation will run until it throws a timeout error. */
timeoutMS?: number;

[kSession]: ClientSession | undefined;
Expand Down
5 changes: 4 additions & 1 deletion src/operations/run_command.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ export type RunCommandOptions = {
session?: ClientSession;
/** The read preference */
readPreference?: ReadPreferenceLike;
/** @internal */
/**
* @experimental
* Specifies the time an operation will run until it throws a timeout error
*/
timeoutMS?: number;
/** @internal */
omitMaxTimeMS?: boolean;
Expand Down
10 changes: 8 additions & 2 deletions src/sessions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -145,7 +145,10 @@ export class ClientSession
[kPinnedConnection]?: Connection;
/** @internal */
[kTxnNumberIncrement]: number;
/** @internal */
/**
* @experimental
* Specifies the time an operation in a given `ClientSession` will run until it throws a timeout error
*/
timeoutMS?: number;

/** @internal */
Expand Down Expand Up @@ -710,6 +713,9 @@ export class ClientSession
* `Promise.allSettled`, `Promise.race`, etc to parallelize operations inside a transaction is
* 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 be part of the transaction and it will not respect timeoutMS.
*
*
* @remarks
* - If all operations successfully complete and the `commitTransaction` operation is successful, then the provided function will return the result of the provided function.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
type CommandStartedEvent,
type CommandSucceededEvent,
Connection,
CursorTimeoutMode,
type Db,
type FindCursor,
GridFSBucket,
Expand Down Expand Up @@ -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(
Expand Down
Loading