From 1513fd70148a97a71e65c32b122766dc73a2f00a Mon Sep 17 00:00:00 2001 From: Sergey Zelenov Date: Thu, 19 Mar 2026 18:38:01 +0100 Subject: [PATCH 1/2] fix(NODE-7459): explicitly call setKeepAlive and setNoDelay on socket (#4879) Co-authored-by: Pavel Safronov --- src/cmap/connect.ts | 20 +++++- test/unit/cmap/connect.test.ts | 112 ++++++++++++++++++++++++++++++++- 2 files changed, 130 insertions(+), 2 deletions(-) diff --git a/src/cmap/connect.ts b/src/cmap/connect.ts index 544ec471a99..69c607c8eb6 100644 --- a/src/cmap/connect.ts +++ b/src/cmap/connect.ts @@ -279,6 +279,15 @@ export async function prepareHandshakeDocument( return handshakeDoc; } +/** + * @internal + * Default TCP keepAlive initial delay in milliseconds. + * Set to half the Azure load balancer idle timeout (240s) to ensure + * probes fire well before cloud LBs (Azure, AWS PrivateLink/NLB) + * drop idle connections. + */ +export const DEFAULT_KEEP_ALIVE_INITIAL_DELAY_MS = 120_000; + /** @public */ export const LEGAL_TLS_SOCKET_OPTIONS = [ 'allowPartialTrustChain', @@ -322,7 +331,7 @@ function parseConnectOptions(options: ConnectionOptions): SocketConnectOpts { (result as Document)[name] = options[name]; } } - result.keepAliveInitialDelay ??= 120000; + result.keepAliveInitialDelay ??= DEFAULT_KEEP_ALIVE_INITIAL_DELAY_MS; result.keepAlive = true; result.noDelay = options.noDelay ?? true; @@ -368,6 +377,9 @@ export async function makeSocket(options: MakeConnectionOptions): Promise void) | null = null; diff --git a/test/unit/cmap/connect.test.ts b/test/unit/cmap/connect.test.ts index a97cb7194a6..3ef116549aa 100644 --- a/test/unit/cmap/connect.test.ts +++ b/test/unit/cmap/connect.test.ts @@ -1,8 +1,18 @@ import { expect } from 'chai'; +import * as fs from 'fs'; +import * as net from 'net'; +import * as path from 'path'; import * as process from 'process'; +import * as sinon from 'sinon'; +import * as tls from 'tls'; import { MongoCredentials } from '../../../src/cmap/auth/mongo_credentials'; -import { connect, prepareHandshakeDocument } from '../../../src/cmap/connect'; +import { + connect, + DEFAULT_KEEP_ALIVE_INITIAL_DELAY_MS, + makeSocket, + prepareHandshakeDocument +} from '../../../src/cmap/connect'; import { type Connection, type ConnectionOptions } from '../../../src/cmap/connection'; import { type ClientMetadata, @@ -434,4 +444,104 @@ describe('Connect Tests', function () { }); }); }); + + describe('makeSocket', function () { + let tlsServer: tls.Server; + let tlsPort: number; + let setKeepAliveSpy: sinon.SinonSpy; + let setNoDelaySpy: sinon.SinonSpy; + + const serverPem = fs.readFileSync( + path.join(__dirname, '../../integration/auth/ssl/server.pem') + ); + + before(function (done) { + // @SECLEVEL=0 allows the legacy test certificate (signed with SHA-1/1024-bit RSA) + // to be accepted by OpenSSL 3.x, which rejects at the default security level. + tlsServer = tls.createServer( + { key: serverPem, cert: serverPem, ciphers: 'DEFAULT:@SECLEVEL=0' }, + () => { + /* empty */ + } + ); + tlsServer.listen(0, '127.0.0.1', () => { + tlsPort = (tlsServer.address() as net.AddressInfo).port; + done(); + }); + }); + + after(function () { + tlsServer?.close(); + }); + + beforeEach(function () { + setKeepAliveSpy = sinon.spy(net.Socket.prototype, 'setKeepAlive'); + setNoDelaySpy = sinon.spy(net.Socket.prototype, 'setNoDelay'); + }); + + afterEach(function () { + sinon.restore(); + }); + + context('when tls is enabled', function () { + it('calls setKeepAlive with default keepAliveInitialDelay', async function () { + const socket = await makeSocket({ + hostAddress: new HostAddress(`127.0.0.1:${tlsPort}`), + tls: true, + rejectUnauthorized: false, + ciphers: 'DEFAULT:@SECLEVEL=0' + } as ConnectionOptions); + socket.destroy(); + + expect(setKeepAliveSpy).to.have.been.calledWith(true, DEFAULT_KEEP_ALIVE_INITIAL_DELAY_MS); + }); + + it('calls setKeepAlive with custom keepAliveInitialDelay', async function () { + const socket = await makeSocket({ + hostAddress: new HostAddress(`127.0.0.1:${tlsPort}`), + tls: true, + rejectUnauthorized: false, + ciphers: 'DEFAULT:@SECLEVEL=0', + keepAliveInitialDelay: 5000 + } as ConnectionOptions); + socket.destroy(); + + expect(setKeepAliveSpy).to.have.been.calledWith(true, 5000); + }); + + it('calls setNoDelay with true by default', async function () { + const socket = await makeSocket({ + hostAddress: new HostAddress(`127.0.0.1:${tlsPort}`), + tls: true, + rejectUnauthorized: false, + ciphers: 'DEFAULT:@SECLEVEL=0' + } as ConnectionOptions); + socket.destroy(); + + expect(setNoDelaySpy).to.have.been.calledWith(true); + }); + }); + + context('when tls is disabled', function () { + it('calls setKeepAlive with default keepAliveInitialDelay', async function () { + const socket = await makeSocket({ + hostAddress: new HostAddress(`127.0.0.1:${tlsPort}`), + tls: false + } as ConnectionOptions); + socket.destroy(); + + expect(setKeepAliveSpy).to.have.been.calledWith(true, DEFAULT_KEEP_ALIVE_INITIAL_DELAY_MS); + }); + + it('calls setNoDelay with true by default', async function () { + const socket = await makeSocket({ + hostAddress: new HostAddress(`127.0.0.1:${tlsPort}`), + tls: false + } as ConnectionOptions); + socket.destroy(); + + expect(setNoDelaySpy).to.have.been.calledWith(true); + }); + }); + }); }); From db0fda557acf507bd7e85cbe95f41af89bdaf908 Mon Sep 17 00:00:00 2001 From: Daria Pardue Date: Mon, 23 Mar 2026 09:18:52 -0400 Subject: [PATCH 2/2] chore: update codeql target for v7.1.x (#4903) --- .github/workflows/codeql.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index fe360b18b69..dc12be9765b 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -2,9 +2,9 @@ name: "CodeQL" on: push: - branches: [ "main", "5.x" ] + branches: [ "main", "v7.1.x" ] pull_request: - branches: [ "main", "5.x" ] + branches: [ "main", "v7.1.x" ] jobs: analyze: