Skip to content

Commit

Permalink
fix(node-http-handler): call socket.setKeepAlive if enabled in http(s…
Browse files Browse the repository at this point in the history
…)Agent (#4561)

Co-authored-by: Trivikram Kamat <16024985+trivikr@users.noreply.github.com>
  • Loading branch information
yenfryherrerafeliz and trivikr committed May 4, 2023
1 parent 0408b01 commit bd16ace
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 0 deletions.
12 changes: 12 additions & 0 deletions packages/node-http-handler/src/node-http-handler.ts
Expand Up @@ -9,6 +9,7 @@ import { getTransformedHeaders } from "./get-transformed-headers";
import { setConnectionTimeout } from "./set-connection-timeout";
import { setSocketTimeout } from "./set-socket-timeout";
import { writeRequestBody } from "./write-request-body";
import { setSocketKeepAlive } from "./set-socket-keep-alive";

/**
* Represents the http options that can be passed to a node http client.
Expand Down Expand Up @@ -151,6 +152,17 @@ export class NodeHttpHandler implements HttpHandler {
};
}

// Workaround for bug report in Node.js https://github.com/nodejs/node/issues/47137
const httpAgent = nodeHttpsOptions.agent;
if (typeof httpAgent === "object" && "keepAlive" in httpAgent) {
setSocketKeepAlive(req, {
// @ts-expect-error keepAlive is not public on httpAgent.
keepAlive: (httpAgent as hAgent).keepAlive,
// @ts-expect-error keepAliveMsecs is not public on httpAgent.
keepAliveMsecs: (httpAgent as hAgent).keepAliveMsecs,
});
}

writeRequestBody(req, request);
});
}
Expand Down
46 changes: 46 additions & 0 deletions packages/node-http-handler/src/set-socket-keep-alive.spec.ts
@@ -0,0 +1,46 @@
import { EventEmitter } from "events";
import { ClientRequest } from "http";
import { Socket } from "net";

import { setSocketKeepAlive } from "./set-socket-keep-alive";

describe("setSocketKeepAlive", () => {
let request: ClientRequest;
let socket: Socket;

beforeEach(() => {
request = new EventEmitter() as ClientRequest;
socket = new Socket();
});

it("should set keepAlive to true", () => {
setSocketKeepAlive(request, { keepAlive: true });

const setKeepAliveSpy = jest.spyOn(socket, "setKeepAlive");
request.emit("socket", socket);

expect(setKeepAliveSpy).toHaveBeenCalled();
expect(setKeepAliveSpy).toHaveBeenCalledWith(true, 0);
});

it("should set keepAlive to true with custom initialDelay", () => {
const initialDelay = 5 * 1000;
setSocketKeepAlive(request, { keepAlive: true, keepAliveMsecs: initialDelay });

const setKeepAliveSpy = jest.spyOn(socket, "setKeepAlive");
request.emit("socket", socket);

expect(setKeepAliveSpy).toHaveBeenCalled();
expect(setKeepAliveSpy).toHaveBeenCalledWith(true, initialDelay);
});

it("should not set keepAlive at all when keepAlive is false", () => {
setSocketKeepAlive(request, { keepAlive: false });

const setKeepAliveSpy = jest.spyOn(socket, "setKeepAlive");
request.emit("socket", socket);

expect(setKeepAliveSpy).not.toHaveBeenCalled();
});
});

16 changes: 16 additions & 0 deletions packages/node-http-handler/src/set-socket-keep-alive.ts
@@ -0,0 +1,16 @@
import { ClientRequest } from "http";

export interface SocketKeepAliveOptions {
keepAlive: boolean;
keepAliveMsecs?: number;
}

export const setSocketKeepAlive = (request: ClientRequest, { keepAlive, keepAliveMsecs }: SocketKeepAliveOptions) => {
if (keepAlive !== true) {
return;
}

request.on("socket", (socket) => {
socket.setKeepAlive(keepAlive, keepAliveMsecs || 0);
});
};

0 comments on commit bd16ace

Please sign in to comment.