@@ -329,8 +329,7 @@ export class HttpStream extends Stream implements SqlOwner {
329329 let promise ;
330330 try {
331331 const request = createRequest ( ) ;
332- const fetch = this . #fetch;
333- promise = fetch ( request ) ;
332+ promise = this . #fetchWithRetry( request ) ;
334333 } catch ( error ) {
335334 promise = Promise . reject ( error ) ;
336335 }
@@ -356,6 +355,20 @@ export class HttpStream extends Stream implements SqlOwner {
356355 } ) ;
357356 }
358357
358+ #fetchWithRetry( request : Request , retryCount : number = 3 , backoff : number = 100 ) : Promise < Response > {
359+ const fetch = this . #fetch;
360+ return fetch ( request ) . catch ( ( error ) => {
361+ if ( isRetryableError ( error ) ) {
362+ if ( retryCount > 0 ) {
363+ return new Promise ( ( resolve ) => setTimeout ( resolve , backoff ) ) . then ( ( ) => {
364+ return this . #fetchWithRetry( request , retryCount - 1 , backoff * 2 ) ;
365+ } ) ;
366+ }
367+ }
368+ throw error ;
369+ } ) ;
370+ }
371+
359372 #createPipelineRequest( pipeline : Array < PipelineEntry > , endpoint : Endpoint ) : Request {
360373 return this . #createRequest< proto . PipelineReqBody > (
361374 new URL ( endpoint . pipelinePath , this . #baseUrl) ,
@@ -417,6 +430,15 @@ export class HttpStream extends Stream implements SqlOwner {
417430 }
418431}
419432
433+ function isRetryableError ( error : any ) : boolean {
434+ if ( ! error . errno ) {
435+ return false ;
436+ }
437+ return error . errno === "EPIPE"
438+ || error . errno === "ECONNREFUSED"
439+ || error . errno === "ECONNRESET" ;
440+ }
441+
420442function handlePipelineResponse ( pipeline : Array < PipelineEntry > , respBody : proto . PipelineRespBody ) : void {
421443 if ( respBody . results . length !== pipeline . length ) {
422444 throw new ProtoError ( "Server returned unexpected number of pipeline results" ) ;
0 commit comments