Description
Checkboxes for prior research
- I've gone through Developer Guide and API reference
- I've checked AWS Forums and StackOverflow.
- I've searched for previous similar issues and didn't find any solution.
Describe the bug
If you send a GetObjectCommand
but only read the returned metadata and never read the body , the S3Client eventually runs out of sockets and gets stuck forever.
I realize the solution is to use HeadObjectCommand
here, but it'd be nice to call this out in the docs someplace. The example for GetObjectCommand
doesn't read the body and thus will lead to leaking connections.
Once the 50 sockets have been used, the S3Client object is dead and will never work again, even after the OS cleans up the stale sockets (By looking at netstat output).
Regression Issue
- Select this option if this issue appears to be a regression.
SDK version number
3.637.0
Which JavaScript Runtime is this issue in?
Node.js
Details of the browser/Node.js/ReactNative version
v20.14.0
Reproduction Steps
const client = new S3Client({
region: getEnv("DATA_REGION"),
requestHandler: new NodeHttpHandler({ socketTimeout: 25000, connectionTimeout: 5000 }),
maxAttempts: 3,
})
for(let i=0;i<=50;i++){
const s3objCmd = new GetObjectCommand({
Bucket: awsBucket,
Key: s3Key,
})
const s3resp = await client.send(s3objCmd)
doSomethingWithMetadata(s3resp.Metadata)
}
Observed Behavior
Without a timeout the 51st GetObjectCommand
hangs forever. With a timeout, you get an error after the socketTimeout
triggers.
Expected Behavior
I expected to continue getting S3 objects or there to be a note in the documentation that I should always calls .Body()
on the response to drain the socket.
I would expect the client itself to garbage collect sockets after the timeout or after the OS closes them.
I would also expect the client to throw an OutOfSockets
error instead of hanging forever or hitting a connection timeout (When it won't ever connect because it is out of sockets)
Possible Solution
The easiest fix is a note in the documentation but I'd appreciate also a different error when out of sockets in the client.
I'm not sure about the expected behavior with regards to draining the socket -- It's nice that I found this typo because of the errors -- I don't want the body here and downloading in the background would be a waste of bytes.
But, it took a long time to figure out what was wrong because the inner workings of the SDK are not really clear. I don't see any examples re-using a client and wasn't sure if that was even allowed. It was only when I found the default maxSockets
parameter on the client that everything fell into place.
Additional Information/Context
No response