diff --git a/gax/src/fallbackServiceStub.ts b/gax/src/fallbackServiceStub.ts index bb7a1b661..04be7810d 100644 --- a/gax/src/fallbackServiceStub.ts +++ b/gax/src/fallbackServiceStub.ts @@ -18,18 +18,40 @@ /* global AbortController */ import nodeFetch from 'node-fetch'; -import {Response as NodeFetchResponse} from 'node-fetch'; +import {Response as NodeFetchResponse, RequestInit} from 'node-fetch'; import {AbortController as NodeAbortController} from 'abort-controller'; -import {hasWindowFetch, hasAbortController} from './featureDetection'; +import {hasWindowFetch, hasAbortController, isNodeJS} from './featureDetection'; import {AuthClient} from './fallback'; import {StreamArrayParser} from './streamArrayParser'; import {pipeline, PipelineSource} from 'stream'; +import type {Agent as HttpAgent} from 'http'; +import type {Agent as HttpsAgent} from 'https'; interface NodeFetchType { (url: RequestInfo, init?: RequestInit): Promise; } +// Node.js before v19 does not enable keepalive by default. +// We'll try to enable it very carefully to make sure we don't break possible non-Node use cases. +// TODO: remove this after Node 18 is EOL. +// More info: https://github.com/node-fetch/node-fetch#custom-agent +let agentOption: + | ((parsedUrl: {protocol: string}) => HttpAgent | HttpsAgent) + | null = null; +if (isNodeJS()) { + const http = require('http'); + const https = require('https'); + const httpAgent = new http.Agent({keepAlive: true}); + const httpsAgent = new https.Agent({keepAlive: true}); + agentOption = (parsedUrl: {protocol: string}) => { + if (parsedUrl.protocol === 'http:') { + return httpAgent; + } + return httpsAgent; + }; +} + export interface FallbackServiceStub { // Compatible with gRPC service stub [method: string]: ( @@ -141,13 +163,16 @@ export function generateServiceStub( method: fetchParameters.method, signal: cancelSignal, }; + if (agentOption) { + fetchRequest.agent = agentOption; + } if ( fetchParameters.method === 'GET' || fetchParameters.method === 'DELETE' ) { delete fetchRequest['body']; } - return fetch(url, fetchRequest); + return fetch(url, fetchRequest as {}); }) .then((response: Response | NodeFetchResponse) => { if (response.ok && rpc.responseStream) {