Skip to content
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

http: remove stale timeout listeners #9440

Closed
wants to merge 10 commits into from

Conversation

karlbohlmark
Copy link

Checklist
  • make -j8 test (UNIX), or vcbuild test nosign (Windows) passes
  • tests and/or benchmarks are included
  • commit message follows commit guidelines
Affected core subsystem(s)

http

Description of change

In order to prevent a memory leak when using keep alive, ensure that the
timeout listener for the request is removed when the response has ended.

This fixes #9268

In order to prevent a memory leak when using keep alive, ensure that the
timeout listener for the request is removed when the response has ended.
@nodejs-github-bot nodejs-github-bot added the http Issues or PRs related to the http subsystem. label Nov 3, 2016
socket.once('timeout', () => req.emit('timeout'));
const emitRequestTimeout = () => req.emit('timeout');
socket.once('timeout', emitRequestTimeout);
req.on('response', (r) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm, I wonder if the response event is emitted in all cases if the request is aborted...will have to dig into that

Copy link
Author

@karlbohlmark karlbohlmark Nov 3, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I don't think it is, but I think the socket is destroyed, which solves the cleanup issue in that case.

agent.destroy();
})
.catch((e) => {
console.log(e);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unless the console.log() is part of the test, I'd prefer to omit the extraneous output

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps instead make this a common.fail()?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could remove the whole catch clause and add a

process.on('unhandledRejection', function () {
  common.fail('A promise rejection was unhandled')
});

Would that be ok?

I want to ensure that the test never hangs

@grahamj
Copy link

grahamj commented Nov 3, 2016

I usually lurk so excuse if I'm being too picky... The patch looks good but perhaps there should there be a test to confirm that this actually fixes the leak? It's possible that something else is also contributing, such as @evanlucas 's concern about end always being emitted or possibly other listeners similarly not being removed.

Just a thought, thanks for the patch!

@plemarquand
Copy link

I just tried this patch locally and it does indeed fix the memory leak we were seeing. 👍

agent,
method: 'GET',
port: undefined,
host: '127.0.0.1',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of 127.0.0.1 throughout the test, can you use common.localhostIPv4.

@karlbohlmark
Copy link
Author

@evanlucas Is there anything more I can do on this? Rebase and squash?

We are currently not able to use the latest LTS (or the latest Current) because of this memory leak. It would be really nice to get any fix in for this.

@Trott
Copy link
Member

Trott commented Nov 10, 2016

/cc @nodejs/http

@mjsalinger
Copy link

This is definitely affecting our ability to use the latest LTS release...

@evanlucas
Copy link
Contributor

Sorry for the delay. I'm still digging in to make sure we don't need to clean up anything else related to the timeout. In the meantime, CI: https://ci.nodejs.org/job/node-test-pull-request/4883/

@evanlucas
Copy link
Contributor

Looks like there is a related test failure on arm. (https://ci.nodejs.org/job/node-test-binary-arm/4752/RUN_SUBSET=3,label=pi1-raspbian-wheezy/tapResults/)

assert.js:85
  throw new assert.AssertionError({
  ^
AssertionError: A promise rejection was unhandled
    at Object.exports.fail (/home/iojs/build/workspace/node-test-binary-arm/test/common.js:443:10)
    at process.<anonymous> (/home/iojs/build/workspace/node-test-binary-arm/test/parallel/test-http-client-timeout-option-listeners.js:22:10)
    at emitTwo (events.js:106:13)
    at process.emit (events.js:191:7)
    at emitPendingUnhandledRejections (internal/process/promises.js:72:22)
    at process._tickCallback (internal/process/next_tick.js:104:7)

port: undefined,
host: common.localhostIPv4,
path: '/',
timeout: 100
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you wrap the timeout in common.platformTimeout()

http.request(options, (response) => {
const sockets = agent.sockets[`${options.host}:${options.port}:`];
if (sockets.length !== 1) {
reject(new Error('Only one socket should be created'));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should there be a return here?

@evanlucas
Copy link
Contributor

@karlbohlmark
Copy link
Author

@evanlucas That failure doesn't seem related, right?

@evanlucas
Copy link
Contributor

@karlbohlmark ah I restarted CI, so I'm not sure which one it was. I'm still doing some additional testing around this to make sure it doesn't affect anything else. We should be able to get this in soon though. Thanks for being patient!

@evanlucas
Copy link
Contributor

/cc @nodejs/http PTAL

socket.once('timeout', () => req.emit('timeout'));
const emitRequestTimeout = () => req.emit('timeout');
socket.once('timeout', emitRequestTimeout);
req.on('response', (r) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you call the argument res for consistency/parity? Is there a reason to use .on instead of .once? The timeout listener is installed with .once().

response.on('end', () => resolve(numListeners));
}).end();
});
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd write the test in simple callback style. Less chance of accidentally swallowing errors and easier to debug because you can simply assert.strictEqual(sockets.length, 1) instead of calling reject().

@italoacasas
Copy link
Contributor

Landed 9a5d475

Thanks for the contribution.

@italoacasas italoacasas closed this Dec 8, 2016
Fishrock123 pushed a commit that referenced this pull request Dec 13, 2016
In order to prevent a memory leak when using keep alive, ensure that the
timeout listener for the request is removed when the response has ended.

PR-URL: #9440
Reviewed-By: Evan Lucas <evanlucas@me.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
@italoacasas italoacasas mentioned this pull request Dec 15, 2016
italoacasas added a commit that referenced this pull request Dec 15, 2016
Notable changes:
- buffer:
  - fix single-character string filling (Anna Henningsen) #9837
  - handle UCS2.fill() properly on BE (Anna Henningsen) #9837
- url:
  -  including base argument in originFor (joyeecheung) #10021
  - improve URLSearchParams spec compliance (Timothy Gu) #9484
- http:
  - remove stale timeout listeners (Karl Böhlmark) #9440
- build:
  - fix node_g target (Daniel Bevenius) #10153

PR-URL: #10277
italoacasas added a commit that referenced this pull request Dec 15, 2016
Notable changes

SEMVER-MINOR
- url:
    - add inspect function to TupleOrigin (Safia Abdalla) #10039
- crypto:
    - allow adding extra certs to well-known CAs (Sam Roberts) #9139

SEMVER-PATCH
- buffer:
    - fix single-character string filling (Anna Henningsen) #9837
    - handle UCS2 .fill() properly on BE (Anna Henningsen) #9837
- url:
    - including base argument in originFor (joyeecheung) #10021
    - improve URLSearchParams spec compliance (Timothy Gu) #9484
- http:
    - remove stale timeout listeners (Karl Böhlmark) #9440
- build:
    - fix node_g target (Daniel Bevenius) #10153
- fs:
    - remove unused argument from copyObject() (Ethan Arrowood) #10041
- timers:
    - fix handling of cleared immediates (hveldstra) #9759

PR-URL: #10277
italoacasas added a commit that referenced this pull request Dec 17, 2016
Notable changes:
* **crypto**:
  - Allow adding extra certificates to well-known CAs. (Sam Roberts)
    [#9139](#9139)
* **buffer**:
  - Fix single-character string filling. (Anna Henningsen)
    [#9837](#9837)
  - Handle UCS2 `.fill()` properly on BE. (Anna Henningsen)
    [#9837](#9837)
* **url**:
  - Add inspect function to TupleOrigin. (Safia Abdalla)
    [#10039](#10039)
  - Including base argument in originFor. (joyeecheung)
    [#10021](#10021)
  - Improve URLSearchParams spec compliance. (Timothy Gu)
    [#9484](#9484)
* **http**:
  - Remove stale timeout listeners. (Karl Böhlmark)
    [#9440](#9440)
* **build**:
  - Fix node_g target. (Daniel Bevenius)
    [#10153](#10153)
* **fs**:
  - Remove unused argument from copyObject(). (EthanArrowood)
    [#10041](#10041)
* **timers**:
  - Fix handling of cleared immediates. (hveldstra)
    [#9759](#9759)
* **src**:
  - Add wrapper for process.emitWarning(). (SamRoberts)
    [#9139](#9139)
  - Fix string format mistake for 32 bit node.(Alex Newman)
    [#10082](#10082)
italoacasas added a commit that referenced this pull request Dec 19, 2016
Notable changes:
* **crypto**: The built-in list of Well-Known CAs (Certificate Authorities) can now
              be extended via a NODE_EXTRA_CA_CERTS environment variable. (Sam Roberts)
              [#9139](#9139)
* **buffer**: buffer.fill() now works properly for the UCS2 encoding on Big-Endian
              machines. (Anna Henningsen) [#9837](#9837)
* **url**:
    - Including base argument in URL.originFor() to meet specification compliance. (joyeecheung)
      [#10021](#10021)
    - Improve URLSearchParams to meet specification compliance. (Timothy Gu)
      [#9484](#9484)
* **http**: Remove stale timeout listeners in order to prevent a memory leak when using
            keep alive. (Karl Böhlmark) [#9440](#9440)
cjihrig added a commit to cjihrig/node that referenced this pull request Dec 20, 2016
Notable changes:

* buffer:
  - buffer.fill() now works properly for the UCS2 encoding on
    Big-Endian machines.
    (Anna Henningsen) nodejs#9837
* cluster:
  - disconnect() now returns a reference to the disconnected
    worker. (Sean Villars)
    nodejs#10019
* crypto:
  - The built-in list of Well-Known CAs (Certificate Authorities)
    can now be extended via a NODE_EXTRA_CA_CERTS environment
    variable. (Sam Roberts)
    nodejs#9139
* http:
  - Remove stale timeout listeners in order to prevent a memory leak
    when using keep alive. (Karl Böhlmark)
    nodejs#9440
* tls:
  - Allow obvious key/passphrase combinations. (Sam Roberts)
    nodejs#10294
* url:
  - Including base argument in URL.originFor() to meet specification
    compliance. (joyeecheung)
    nodejs#10021
  - Improve URLSearchParams to meet specification compliance.
    (Timothy Gu) nodejs#9484

PR-URL: nodejs#10277
cjihrig added a commit to cjihrig/node that referenced this pull request Dec 20, 2016
Notable changes:

* buffer:
  - buffer.fill() now works properly for the UCS2 encoding on
    Big-Endian machines.
    (Anna Henningsen) nodejs#9837
* cluster:
  - disconnect() now returns a reference to the disconnected
    worker. (Sean Villars)
    nodejs#10019
* crypto:
  - The built-in list of Well-Known CAs (Certificate Authorities)
    can now be extended via a NODE_EXTRA_CA_CERTS environment
    variable. (Sam Roberts)
    nodejs#9139
* http:
  - Remove stale timeout listeners in order to prevent a memory leak
    when using keep alive. (Karl Böhlmark)
    nodejs#9440
* tls:
  - Allow obvious key/passphrase combinations. (Sam Roberts)
    nodejs#10294
* url:
  - Including base argument in URL.originFor() to meet specification
    compliance. (joyeecheung)
    nodejs#10021
  - Improve URLSearchParams to meet specification compliance.
    (Timothy Gu) nodejs#9484

PR-URL: nodejs#10277
cjihrig added a commit that referenced this pull request Dec 20, 2016
Notable changes:

* buffer:
  - buffer.fill() now works properly for the UCS2 encoding on
    Big-Endian machines.
    (Anna Henningsen) #9837
* cluster:
  - disconnect() now returns a reference to the disconnected
    worker. (Sean Villars)
    #10019
* crypto:
  - The built-in list of Well-Known CAs (Certificate Authorities)
    can now be extended via a NODE_EXTRA_CA_CERTS environment
    variable. (Sam Roberts)
    #9139
* http:
  - Remove stale timeout listeners in order to prevent a memory leak
    when using keep alive. (Karl Böhlmark)
    #9440
* tls:
  - Allow obvious key/passphrase combinations. (Sam Roberts)
    #10294
* url:
  - Including base argument in URL.originFor() to meet specification
    compliance. (joyeecheung)
    #10021
  - Improve URLSearchParams to meet specification compliance.
    (Timothy Gu) #9484

PR-URL: #10277
imyller added a commit to imyller/meta-nodejs that referenced this pull request Dec 21, 2016
    Notable changes:

    * buffer:
      - buffer.fill() now works properly for the UCS2 encoding on
        Big-Endian machines.
        (Anna Henningsen) nodejs/node#9837
    * cluster:
      - disconnect() now returns a reference to the disconnected
        worker. (Sean Villars)
        nodejs/node#10019
    * crypto:
      - The built-in list of Well-Known CAs (Certificate Authorities)
        can now be extended via a NODE_EXTRA_CA_CERTS environment
        variable. (Sam Roberts)
        nodejs/node#9139
    * http:
      - Remove stale timeout listeners in order to prevent a memory leak
        when using keep alive. (Karl Bohlmark)
        nodejs/node#9440
    * tls:
      - Allow obvious key/passphrase combinations. (Sam Roberts)
        nodejs/node#10294
    * url:
      - Including base argument in URL.originFor() to meet specification
        compliance. (joyeecheung)
        nodejs/node#10021
      - Improve URLSearchParams to meet specification compliance.
        (Timothy Gu) nodejs/node#9484

    PR-URL: nodejs/node#10277

Signed-off-by: Ilkka Myller <ilkka.myller@nodefield.com>
MylesBorins pushed a commit that referenced this pull request Jan 16, 2017
In order to prevent a memory leak when using keep alive, ensure that the
timeout listener for the request is removed when the response has ended.

PR-URL: #9440
Reviewed-By: Evan Lucas <evanlucas@me.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
@MylesBorins
Copy link
Contributor

I've landed this in v6.x-staging. I do not believe this needs to be included in the v4.x release line. Please let me know if I am mistakedn

@sindreij
Copy link

When will this land in 6.x?

@gibfahn
Copy link
Member

gibfahn commented Jan 19, 2017

@sindreij

I've landed this in v6.x-staging.

This means it should be in the next v6.x release, which is planned for February 21st (not a firm date, see this issue).

MylesBorins pushed a commit that referenced this pull request Jan 24, 2017
In order to prevent a memory leak when using keep alive, ensure that the
timeout listener for the request is removed when the response has ended.

PR-URL: #9440
Reviewed-By: Evan Lucas <evanlucas@me.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
@MylesBorins MylesBorins mentioned this pull request Jan 24, 2017
MylesBorins pushed a commit that referenced this pull request Jan 31, 2017
In order to prevent a memory leak when using keep alive, ensure that the
timeout listener for the request is removed when the response has ended.

PR-URL: #9440
Reviewed-By: Evan Lucas <evanlucas@me.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
http Issues or PRs related to the http subsystem.
Projects
None yet