Skip to content

Commit

Permalink
docs(NODE-6456): document CSOT pt 1 (#4292)
Browse files Browse the repository at this point in the history
Co-authored-by: Neal Beeken <[email protected]>
Co-authored-by: Aditi Khare <[email protected]>
  • Loading branch information
3 people authored and dariakp committed Nov 6, 2024
1 parent fda0b89 commit 7d548a8
Show file tree
Hide file tree
Showing 14 changed files with 154 additions and 57 deletions.
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

0 comments on commit 7d548a8

Please sign in to comment.