@@ -29,7 +29,7 @@ import { type CancellationToken, TypedEventEmitter } from '../mongo_types';
29
29
import { ReadPreference , type ReadPreferenceLike } from '../read_preference' ;
30
30
import { ServerType } from '../sdam/common' ;
31
31
import { applySession , type ClientSession , updateSessionFromResponse } from '../sessions' ;
32
- import { type Timeout } from '../timeout' ;
32
+ import { Timeout } from '../timeout' ;
33
33
import {
34
34
BufferPool ,
35
35
calculateDurationInMs ,
@@ -59,6 +59,7 @@ import {
59
59
type WriteProtocolMessageType
60
60
} from './commands' ;
61
61
import type { Stream } from './connect' ;
62
+ import { type ConnectionPool } from './connection_pool' ;
62
63
import type { ClientMetadata } from './handshake/client_metadata' ;
63
64
import { StreamDescription , type StreamDescriptionOptions } from './stream_description' ;
64
65
import { type CompressorName , decompressResponse } from './wire_protocol/compression' ;
@@ -183,6 +184,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
183
184
* Once connection is established, command logging can log events (if enabled)
184
185
*/
185
186
public established : boolean ;
187
+ public pool ?: ConnectionPool ;
186
188
/** Indicates that the connection (including underlying TCP socket) has been closed. */
187
189
public closed = false ;
188
190
@@ -279,6 +281,10 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
279
281
) ;
280
282
}
281
283
284
+ private get minRoundTripTime ( ) : number {
285
+ return this . pool ?. server . description . minRoundTripTime ?? 0 ;
286
+ }
287
+
282
288
public markAvailable ( ) : void {
283
289
this . lastUseTime = now ( ) ;
284
290
}
@@ -343,6 +349,10 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
343
349
344
350
let clusterTime = this . clusterTime ;
345
351
352
+ if ( Timeout . is ( options . timeout ) && options . timeout . duration > 0 ) {
353
+ cmd . maxTimeMS = options . timeout . getMaxTimeMS ( this . minRoundTripTime ) ;
354
+ }
355
+
346
356
if ( this . serverApi ) {
347
357
const { version, strict, deprecationErrors } = this . serverApi ;
348
358
cmd . apiVersion = version ;
@@ -432,7 +442,8 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
432
442
try {
433
443
await this . writeCommand ( message , {
434
444
agreedCompressor : this . description . compressor ?? 'none' ,
435
- zlibCompressionLevel : this . description . zlibCompressionLevel
445
+ zlibCompressionLevel : this . description . zlibCompressionLevel ,
446
+ timeout : options . timeout
436
447
} ) ;
437
448
438
449
if ( options . noResponse ) {
@@ -442,7 +453,7 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
442
453
443
454
this . throwIfAborted ( ) ;
444
455
445
- for await ( const response of this . readMany ( ) ) {
456
+ for await ( const response of this . readMany ( { timeout : options . timeout } ) ) {
446
457
this . socket . setTimeout ( 0 ) ;
447
458
const bson = response . parse ( ) ;
448
459
@@ -635,7 +646,11 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
635
646
*/
636
647
private async writeCommand (
637
648
command : WriteProtocolMessageType ,
638
- options : { agreedCompressor ?: CompressorName ; zlibCompressionLevel ?: number }
649
+ options : {
650
+ agreedCompressor ?: CompressorName ;
651
+ zlibCompressionLevel ?: number ;
652
+ timeout ?: Timeout | null ;
653
+ }
639
654
) : Promise < void > {
640
655
const finalCommand =
641
656
options . agreedCompressor === 'none' || ! OpCompressedRequest . canCompress ( command )
@@ -647,8 +662,15 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
647
662
648
663
const buffer = Buffer . concat ( await finalCommand . toBin ( ) ) ;
649
664
650
- if ( this . socket . write ( buffer ) ) return ;
651
- return await once ( this . socket , 'drain' ) ;
665
+ if ( this . socket . write ( buffer ) ) {
666
+ return ;
667
+ }
668
+ const drain = once ( this . socket , 'drain' ) ;
669
+
670
+ if ( options . timeout ) {
671
+ await Promise . race ( [ drain , options . timeout ] ) ;
672
+ }
673
+ await drain ;
652
674
}
653
675
654
676
/**
@@ -660,9 +682,11 @@ export class Connection extends TypedEventEmitter<ConnectionEvents> {
660
682
*
661
683
* Note that `for-await` loops call `return` automatically when the loop is exited.
662
684
*/
663
- private async * readMany ( ) : AsyncGenerator < OpMsgResponse | OpReply > {
685
+ private async * readMany ( options : {
686
+ timeout ?: Timeout | null ;
687
+ } ) : AsyncGenerator < OpMsgResponse | OpReply > {
664
688
try {
665
- this . dataEvents = onData ( this . messageStream ) ;
689
+ this . dataEvents = onData ( this . messageStream , options ) ;
666
690
for await ( const message of this . dataEvents ) {
667
691
const response = await decompressResponse ( message ) ;
668
692
yield response ;
0 commit comments