@@ -48,6 +48,7 @@ export interface SASLOptions {
4848
4949export interface ConnectionOptions {
5050 connectTimeout ?: number
51+ requestTimeout ?: number
5152 maxInflights ?: number
5253 tls ?: TLSConnectionOptions
5354 tlsServerName ?: string | boolean
@@ -66,6 +67,8 @@ export interface Request {
6667 parser : ResponseParser < unknown >
6768 callback : Callback < any >
6869 diagnostic : Record < string , unknown >
70+ timeoutHandle : NodeJS . Timeout | null
71+ timedOut : boolean
6972}
7073
7174export const ConnectionStatuses = {
@@ -78,11 +81,11 @@ export const ConnectionStatuses = {
7881 ERROR : 'error'
7982} as const
8083
81- export type ConnectionStatus = keyof typeof ConnectionStatuses
82- export type ConnectionStatusValue = ( typeof ConnectionStatuses ) [ keyof typeof ConnectionStatuses ]
84+ export type ConnectionStatus = ( typeof ConnectionStatuses ) [ keyof typeof ConnectionStatuses ]
8385
84- export const defaultOptions : ConnectionOptions = {
86+ export const defaultOptions = {
8587 connectTimeout : 5000 ,
88+ requestTimeout : 30000 ,
8689 maxInflights : 5
8790}
8891
@@ -92,7 +95,7 @@ export class Connection extends EventEmitter {
9295 #host: string | undefined
9396 #port: number | undefined
9497 #options: ConnectionOptions
95- #status: ConnectionStatusValue
98+ #status: ConnectionStatus
9699 #instanceId: number
97100 #clientId: string | undefined
98101 // @ts -ignore This is used just for debugging
@@ -143,7 +146,7 @@ export class Connection extends EventEmitter {
143146 return this . #instanceId
144147 }
145148
146- get status ( ) : ConnectionStatusValue {
149+ get status ( ) : ConnectionStatus {
147150 return this . #status
148151 }
149152
@@ -187,7 +190,7 @@ export class Connection extends EventEmitter {
187190 typeof this . #options. tlsServerName === 'string' ? this . #options. tlsServerName : host
188191 }
189192
190- const connectionTimeoutHandler = ( ) => {
193+ const connectingSocketTimeoutHandler = ( ) => {
191194 const error = new TimeoutError ( `Connection to ${ host } :${ port } timed out.` )
192195 diagnosticContext . error = error
193196 this . #socket. destroy ( )
@@ -201,7 +204,7 @@ export class Connection extends EventEmitter {
201204 connectionsConnectsChannel . asyncEnd . publish ( diagnosticContext )
202205 }
203206
204- const connectionErrorHandler = ( error : Error ) => {
207+ const connectingSocketErrorHandler = ( error : Error ) => {
205208 this . #onConnectionError( host , port , diagnosticContext , error )
206209 }
207210
@@ -216,10 +219,10 @@ export class Connection extends EventEmitter {
216219 this . #socket. setNoDelay ( true )
217220
218221 this . #socket. once ( this . #options. tls ? 'secureConnect' : 'connect' , ( ) => {
219- this . #socket. removeListener ( 'timeout' , connectionTimeoutHandler )
220- this . #socket. removeListener ( 'error' , connectionErrorHandler )
222+ this . #socket. removeListener ( 'timeout' , connectingSocketTimeoutHandler )
223+ this . #socket. removeListener ( 'error' , connectingSocketErrorHandler )
221224
222- this . #socket. on ( 'error' , this . #onError . bind ( this ) )
225+ this . #socket. on ( 'error' , this . #connectedSocketErrorHandler . bind ( this ) )
223226 this . #socket. on ( 'data' , this . #onData. bind ( this ) )
224227 if ( this . #handleBackPressure) {
225228 this . #socket. on ( 'drain' , this . #onDrain. bind ( this ) )
@@ -235,8 +238,8 @@ export class Connection extends EventEmitter {
235238 }
236239 } )
237240
238- this . #socket. once ( 'timeout' , connectionTimeoutHandler )
239- this . #socket. once ( 'error' , connectionErrorHandler )
241+ this . #socket. once ( 'timeout' , connectingSocketTimeoutHandler )
242+ this . #socket. once ( 'error' , connectingSocketErrorHandler )
240243 } catch ( error ) {
241244 this . #status = ConnectionStatuses . ERROR
242245
@@ -364,11 +367,23 @@ export class Connection extends EventEmitter {
364367 callback : null as unknown as Callback < any > , // Will be set later
365368 hasResponseHeaderTaggedFields,
366369 noResponse : payload . context . noResponse ?? false ,
367- diagnostic
370+ diagnostic,
371+ timeoutHandle : null ,
372+ timedOut : false
368373 }
369374
370375 this . #requestsQueue. push ( fastQueueCallback => {
371- request . callback = fastQueueCallback
376+ request . callback = ( error : Error | null , payload : any ) => {
377+ clearTimeout ( request . timeoutHandle ! )
378+ request . timeoutHandle = null
379+ fastQueueCallback ( error , payload )
380+ }
381+ if ( ! request . noResponse ) {
382+ request . timeoutHandle = setTimeout ( ( ) => {
383+ request . timedOut = true
384+ request . callback ( new TimeoutError ( 'Request timed out' ) , null )
385+ } , this . #options. requestTimeout )
386+ }
372387
373388 if ( this . #socketMustBeDrained) {
374389 this . #afterDrainRequests. push ( request )
@@ -616,7 +631,11 @@ export class Connection extends EventEmitter {
616631
617632 this . #inflightRequests. delete ( correlationId )
618633
619- const { apiKey, apiVersion, hasResponseHeaderTaggedFields, parser, callback } = request
634+ const { apiKey, apiVersion, hasResponseHeaderTaggedFields, parser, callback, timedOut } = request
635+
636+ if ( timedOut ) {
637+ return
638+ }
620639
621640 let deserialized : any
622641 let responseError : Error | null = null
@@ -704,7 +723,7 @@ export class Connection extends EventEmitter {
704723 }
705724 }
706725
707- #onError ( error : Error ) : void {
726+ #connectedSocketErrorHandler ( error : Error ) : void {
708727 clearTimeout ( this . #reauthenticationTimeout)
709728 this . emit ( 'error' , new NetworkError ( 'Connection error' , { cause : error } ) )
710729 }
0 commit comments