@@ -5,12 +5,14 @@ import { csotMin, noop } from './utils';
55
66/** @internal */
77export class TimeoutError extends Error {
8+ duration : number ;
89 override get name ( ) : 'TimeoutError' {
910 return 'TimeoutError' ;
1011 }
1112
12- constructor ( message : string , options ? : { cause ?: Error } ) {
13+ constructor ( message : string , options : { cause ?: Error ; duration : number } ) {
1314 super ( message , options ) ;
15+ this . duration = options . duration ;
1416 }
1517
1618 static is ( error : unknown ) : error is TimeoutError {
@@ -52,7 +54,12 @@ export class Timeout extends Promise<never> {
5254 }
5355
5456 /** Create a new timeout that expires in `duration` ms */
55- private constructor ( executor : Executor = ( ) => null , duration : number , unref = true ) {
57+ private constructor (
58+ executor : Executor = ( ) => null ,
59+ duration : number ,
60+ unref = true ,
61+ rejection : Error | null = null
62+ ) {
5663 let reject ! : Reject ;
5764 if ( duration < 0 ) {
5865 throw new MongoInvalidArgumentError ( 'Cannot create a Timeout with a negative duration' ) ;
@@ -71,13 +78,15 @@ export class Timeout extends Promise<never> {
7178 this . id = setTimeout ( ( ) => {
7279 this . ended = Math . trunc ( performance . now ( ) ) ;
7380 this . timedOut = true ;
74- reject ( new TimeoutError ( `Expired after ${ duration } ms` ) ) ;
81+ reject ( new TimeoutError ( `Expired after ${ duration } ms` , { duration } ) ) ;
7582 } , this . duration ) ;
7683 if ( typeof this . id . unref === 'function' && unref ) {
7784 // Ensure we do not keep the Node.js event loop running
7885 this . id . unref ( ) ;
7986 }
8087 }
88+
89+ if ( rejection != null ) reject ( rejection ) ;
8190 }
8291
8392 /**
@@ -90,7 +99,7 @@ export class Timeout extends Promise<never> {
9099 }
91100
92101 throwIfExpired ( ) : void {
93- if ( this . timedOut ) throw new TimeoutError ( 'Timed out' ) ;
102+ if ( this . timedOut ) throw new TimeoutError ( 'Timed out' , { duration : this . duration } ) ;
94103 }
95104
96105 public static expires ( durationMS : number , unref ?: boolean ) : Timeout {
@@ -108,6 +117,10 @@ export class Timeout extends Promise<never> {
108117 typeof timeout . then === 'function'
109118 ) ;
110119 }
120+
121+ static override reject ( rejection ?: Error ) : Timeout {
122+ return new Timeout ( undefined , 0 , true , rejection ) ;
123+ }
111124}
112125
113126/** @internal */
@@ -218,8 +231,8 @@ export class CSOTTimeoutContext extends TimeoutContext {
218231 if ( typeof this . _serverSelectionTimeout !== 'object' || this . _serverSelectionTimeout ?. cleared ) {
219232 const { remainingTimeMS, serverSelectionTimeoutMS } = this ;
220233 if ( remainingTimeMS <= 0 )
221- throw new MongoOperationTimeoutError (
222- `Timed out in server selection after ${ this . timeoutMS } ms`
234+ return Timeout . reject (
235+ new MongoOperationTimeoutError ( `Timed out in server selection after ${ this . timeoutMS } ms` )
223236 ) ;
224237 const usingServerSelectionTimeoutMS =
225238 serverSelectionTimeoutMS !== 0 &&
@@ -247,8 +260,10 @@ export class CSOTTimeoutContext extends TimeoutContext {
247260 // null or Timeout
248261 this . _connectionCheckoutTimeout = this . _serverSelectionTimeout ;
249262 } else {
250- throw new MongoRuntimeError (
251- 'Unreachable. If you are seeing this error, please file a ticket on the NODE driver project on Jira'
263+ return Timeout . reject (
264+ new MongoRuntimeError (
265+ 'Unreachable. If you are seeing this error, please file a ticket on the NODE driver project on Jira'
266+ )
252267 ) ;
253268 }
254269 }
@@ -259,14 +274,14 @@ export class CSOTTimeoutContext extends TimeoutContext {
259274 const { remainingTimeMS } = this ;
260275 if ( ! Number . isFinite ( remainingTimeMS ) ) return null ;
261276 if ( remainingTimeMS > 0 ) return Timeout . expires ( remainingTimeMS ) ;
262- throw new MongoOperationTimeoutError ( 'Timed out before socket write' ) ;
277+ return Timeout . reject ( new MongoOperationTimeoutError ( 'Timed out before socket write' ) ) ;
263278 }
264279
265280 get timeoutForSocketRead ( ) : Timeout | null {
266281 const { remainingTimeMS } = this ;
267282 if ( ! Number . isFinite ( remainingTimeMS ) ) return null ;
268283 if ( remainingTimeMS > 0 ) return Timeout . expires ( remainingTimeMS ) ;
269- throw new MongoOperationTimeoutError ( 'Timed out before socket read' ) ;
284+ return Timeout . reject ( new MongoOperationTimeoutError ( 'Timed out before socket read' ) ) ;
270285 }
271286}
272287
0 commit comments