From 56a665f7210cc15921945cb1b5949e886d162b21 Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Wed, 29 Apr 2026 22:10:52 +0000 Subject: [PATCH 1/2] perf(node-http-handler): cache 100-continue agents at module level --- .../src/node-http-handler.ts | 33 +++++++++++++++---- 1 file changed, 27 insertions(+), 6 deletions(-) diff --git a/packages/node-http-handler/src/node-http-handler.ts b/packages/node-http-handler/src/node-http-handler.ts index 1e0082a725b..4e3dede1177 100644 --- a/packages/node-http-handler/src/node-http-handler.ts +++ b/packages/node-http-handler/src/node-http-handler.ts @@ -33,6 +33,14 @@ export const DEFAULT_REQUEST_TIMEOUT = 0; let hAgent: { new (...args: any): hAgentType } | undefined = undefined; let hRequest: typeof hRequestType | undefined = undefined; +/** + * Cached agents for 100-continue requests, shared across all NodeHttpHandler instances. + * Reusing a single agent per protocol avoids GC pressure from creating a new Agent + * on every 100-continue request (e.g., S3 PutObject workloads). + */ +let continueHttpAgent: hAgentType | undefined = undefined; +let continueHttpsAgent: hsAgent | undefined = undefined; + /** * @public * A request handler that uses the Node.js http and https modules. @@ -182,12 +190,25 @@ or increase socketAcquisitionWarningTimeout=(millis) in the NodeHttpHandler conf // Because awaiting 100-continue desynchronizes the request and request body transmission, // such requests must be offloaded to a separate Agent instance. // Additional logic will exist on the client using this handler to determine whether to add the header at all. - agent = new (isSSL ? hsAgent : hAgent!)({ - keepAlive: false, - // This is an explicit value matching the default (Infinity). - // This should allow the connection to close cleanly after making the single request. - maxSockets: Infinity, - }); + // A single cached agent per protocol is reused to avoid GC pressure from creating + // a new Agent on every 100-continue request (e.g., S3 PutObject workloads). + if (isSSL) { + if (!continueHttpsAgent) { + continueHttpsAgent = new hsAgent({ + keepAlive: false, + maxSockets: Infinity, + }); + } + agent = continueHttpsAgent; + } else { + if (!continueHttpAgent) { + continueHttpAgent = new hAgent!({ + keepAlive: false, + maxSockets: Infinity, + }); + } + agent = continueHttpAgent; + } } // If the request is taking a long time, check socket usage and potentially warn. From 714d232d87d5680edd4788b75d364a49544e2299 Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Wed, 29 Apr 2026 22:11:26 +0000 Subject: [PATCH 2/2] chore: yarn changeset --- .changeset/gentle-brooms-compete.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/gentle-brooms-compete.md diff --git a/.changeset/gentle-brooms-compete.md b/.changeset/gentle-brooms-compete.md new file mode 100644 index 00000000000..877bbf2997a --- /dev/null +++ b/.changeset/gentle-brooms-compete.md @@ -0,0 +1,5 @@ +--- +"@smithy/node-http-handler": patch +--- + +Cache 100-continue agents at module level