From 5ed855a0ceab757facbacb132ca59f9af6673865 Mon Sep 17 00:00:00 2001 From: Jackie Tung Date: Tue, 7 Apr 2026 14:51:43 -0700 Subject: [PATCH] Support configurable maxSockets for HTTP agents The SDK creates HTTP agents with keepAlive: true but uses the Node.js default maxSockets: Infinity. In high-throughput server environments, concurrent track() calls can open an unbounded number of TCP connections to Mixpanel's API, which can exhaust file descriptors or trigger rate limits. This adds support for a maxSockets init config option that gets passed through to the underlying http.Agent / https.Agent. When not set, behavior is unchanged (defaults to Infinity). Usage: var mixpanel = Mixpanel.init('token', { maxSockets: 10 }); Confab-Link: https://confab.nooks.in/sessions/e7243277-5942-4965-8abe-99b18914a204 --- lib/mixpanel-node.js | 5 +++-- readme.md | 5 +++++ test/send_request.js | 23 +++++++++++++++++++++++ 3 files changed, 31 insertions(+), 2 deletions(-) diff --git a/lib/mixpanel-node.js b/lib/mixpanel-node.js index d7cdb85..c8d4abe 100644 --- a/lib/mixpanel-node.js +++ b/lib/mixpanel-node.js @@ -49,13 +49,14 @@ const create_client = function (token, config) { config: { ...DEFAULT_CONFIG }, }; const { keepAlive } = metrics.config; + const maxSockets = config && config.maxSockets; // mixpanel constants const MAX_BATCH_SIZE = 50; const REQUEST_LIBS = { http, https }; const REQUEST_AGENTS = { - http: new http.Agent({ keepAlive }), - https: new https.Agent({ keepAlive }), + http: new http.Agent({ keepAlive, maxSockets }), + https: new https.Agent({ keepAlive, maxSockets }), }; const proxyPath = process.env.HTTPS_PROXY || process.env.HTTP_PROXY; const proxyAgent = proxyPath diff --git a/readme.md b/readme.md index decd413..57e5ca8 100644 --- a/readme.md +++ b/readme.md @@ -28,6 +28,11 @@ var mixpanel = Mixpanel.init("", { keepAlive: false, }); +// limit the number of concurrent connections to Mixpanel +var mixpanel = Mixpanel.init("", { + maxSockets: 10, +}); + // pass the custom logger (default is console) var mixpanel = Mixpanel.init("", { debug: true, diff --git a/test/send_request.js b/test/send_request.js index 01be8dc..b77c6c3 100644 --- a/test/send_request.js +++ b/test/send_request.js @@ -182,6 +182,29 @@ describe("send_request", () => { expect(getConfig.agent).toBe(agent); }); + it("uses custom maxSockets when configured", () => { + const agent = new https.Agent({ keepAlive: true }); + const httpsStub = { + request: vi.fn().mockImplementation((_, cb) => { + cb(res); + return http_emitter; + }), + Agent: vi.fn().mockImplementation(function () { + return agent; + }), + }; + delete process.env.HTTP_PROXY; + delete process.env.HTTPS_PROXY; + Mixpanel = proxyquire("../lib/mixpanel-node", { + https: httpsStub, + }); + const proxyMixpanel = Mixpanel.init("token", { maxSockets: 10 }); + proxyMixpanel.send_request({ endpoint: "", data: {} }); + + const agentOpts = httpsStub.Agent.mock.calls[0][0]; + expect(agentOpts.maxSockets).toBe(10); + }); + it("uses correct hostname", () => { const host = "testhost.fakedomain"; const customHostnameMixpanel = Mixpanel.init("token", { host: host });