New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Leaking 'connect' handlers with new timeout support #2438
Comments
I haven't yet written a test to reproduce it, but I believe the connect listener should be removed somewhere near here: Line 795 in fae254e
|
ping @mscdex |
Thanks for the quick fix. I'll deploy a server that uses that branch and see if the memory usage is stable again. It will be a couple of hours to get good data |
Your code looked good to me, but when I deployed, I still see leaking 'connect' handlers. I'm sure that I'm running the right version because the leaked functions are named 'onReqSockConnect'. I don't know why it would matter, but something I didn't mention before is that my sockets are all TLS sockets. Looking at the code again, perhaps the 'connect' listener is also leaking if an error occurs while connecting. Could Line 821 in fae254e
|
@mscdex with the latest fix, including the cleanup on error, it seems like the the memory leak is much smaller. I let the patched version run overnight and then I looked at a heapdump this morning. Instead of seeing 500+ leaked 'connect' handlers, I now see 20-50 connect I don't know the code well, but I would have expected 0-1 handlers. Maybe there is still another edge case that's not cleaning up quite right, but it's much less severe than it was. |
Scratch that, the correct patch was deployed and the leak remains. After more time during the day, I see see a high number of 'connect' listeners leaked. |
I've also noticed 'connect' listeners leak after update to 2.76. It's plain socket with http.Agent and keep alive enabled. Disabling keep alive fixed the issue for me. |
Have spotted this as well making TLS connections. Getting regular errors with 2.76.0:
I don't see the same issue in 2.75.0. |
/cc @mscdex |
@mdlavin @morus12 @robinjmurphy can you provide a short code example to reproduce the issue? |
Hi @simov I'll try and put a little script together to reproduce. |
This code triggers a warning after 11 requests. The warning doesn't appear if I remove the 'use strict';
const request = require('request').defaults({
forever: true,
timeout: 2000
});
function makeRequest() {
request('https://raw.githubusercontent.com/request/request/master/README.md', (err, res) => {
if (err) throw err;
console.log((new Date()).toISOString(), res.statusCode, res.request.href);
setTimeout(makeRequest, 100);
});
}
makeRequest();
Request 2.76.0. Node 4.4.7. Tested on macOS and CentOS |
@robinjmurphy Thanks for the repro. I've updated my PR at #2439 @mdlavin Can you also try my PR again? |
This commit ensures that both a 'connect' timer only starts when a new socket is being used for a request and that the 'connect' timer callback is removed in more places. Fixes: request#2438
This commit ensures that both a 'connect' timer only starts when a new socket is being used for a request and that the 'connect' timer is stopped in more places. Fixes: request#2438
This commit ensures that both a 'connect' timer only starts when a new socket is being used for a request and that the 'connect' timer is stopped in more places. Fixes: request#2438
I'm not sure if the problem discussed in this issue is the same as what we found, but we had some unit tests that started failing with 2.76.0 (they still work with 2.75.0). We're simulating a series of several requests using I've tried the set of tests with the latest commit on this PR ( |
@cgrayson Can you provide a simple example that exhibits the incorrect behavior? |
@cgrayson we saw the same with Nock using |
Assuming this is in var nock = require('nock');
var request = require('request');
var runTest = function() {
nock('http://foobar.com').post('/baz').delayConnection(2000).reply(200, '{"answer": 42}', {});
var timeoutMs = 1000;
request({uri: 'http://foobar.com/baz', method: 'POST', timeout: timeoutMs}, function(err, response, body) {
if (err)
console.log("Yay, the request timed out (as it should have): ", err);
else
console.log("Oops, there was no `err`; the request should have timed out");
});
};
runTest(); When that uses 2.76.0, the timeout does not occur, with 2.75.0, it does: |
Ok, the problem here is that EDIT: I've submitted an issue about this here. |
@mscdex I missed your comment about re-attempting with the new patch. I'm deploying the change now and will watch it today. |
@mscdex the new version looks good to me. I deployed it this morning and it ran for a couple hours under user load without any leaking 'connect' handlers. |
Any ETA on patch version on npm? |
@ZJONSSON If @robinjmurphy can confirm the latest changes to the PR are working them too, then I think it should good to merge, there will still be a problem with |
Will get this tested today for you @mscdex |
Re-ran my own test and it's now working against your |
@robinjmurphy Awesome, thanks for the feedback! |
The patch is published. Good job everyone! |
@morus12 hi, can you show the code for disable the keep alive? thankyou |
@kazaff I'm using nodejs 4.x - it's off by default. |
After adopting 2.76.0 I noticed that the memory on some of our servers using request started to grow when it was not growing before. I took a heap snapshot, and it looked like there were 1000+ 'connect' listeners on a TLS socket, holding on to other memory as a result.
It seems like the 'connect' listener on a socket might not be removed if there is a timeout connecting in the new timeout implementation.
Once I reverted back to 2.75.0, the memory leak was gone.
The text was updated successfully, but these errors were encountered: