-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Description
- I've searched for any related issues and avoided creating a duplicate
issue.
Description
Setting a handshake timeout for a connection doesn't work if the socket never connects.
I want my app to fail fast if it can't connect to an endpoint, but I found that if I set a handshakeTimeout of 5 seconds and configured my app to talk to a known machine but on a port that just silently drops connecting packets, then it didn't time out in 5 seconds but instead would get a global ETIMEDOUT error.
Looking at the code for websocket.js it does this:
var req = (this._req = httpObj.get(options));
if (options.handshakeTimeout) {
req.on('timeout', () => {
abortHandshake(this, req, 'Opening handshake has timed out');
});
}
but I note that the advice for this is to wait for a socket to be assigned before setting a timeout handler. Testing this myself, I also found that just waiting for a socket wasn't enough to get the https library to handle the timeout properly, I had to also set an empty socket timeout handler on the socket itself.
So if I rewrite the code above as:
this._req = httpObj.get(requestOptions)
this._req.on("socket", socket => {
if (options.handshakeTimeout) {
this._req.setTimeout(options.handshakeTimeout, () => {
this._req.abort()
this.finalize(new Error("opening handshake has timed out"))
})
socket.setTimeout(options.handshakeTimeout, () => {
// no-op - just causes above request setTimeout to work
})
}
})
(bearing in mind you appear to have made the req var local between my version and HEAD) then I get successful 5 second timeout errors from websockets.
If you like I can make a PR for the change, I just want to make sure it's not some platform dependent issue or other strange workaround.
Thanks!
Reproducible in:
- version: 6.1.3
- Node.js version(s): 10.9.0
- OS version(s): MacOS 10.13.6
Steps to reproduce:
-
Create a Websockets instance connecting to a known machine and port that drops packets
-
Set a handshakeTimeout of 5 seconds
-
Set a timeout handler and see that it does not time out in 5 seconds but instead waits the minute or two for the global error handler to fire.
Expected result:
Timeout handler to fire
Actual result:
no timeout fired