Uh oh!
There was an error while loading. Please reload this page.
http: Change free sockets behavior to LIFO from FIFO. - #31526
http: Change free sockets behavior to LIFO from FIFO.#31526rustyconover wants to merge 2 commits into
Conversation
On the other hand sockets that have not been used in a while might unnecessarily timeout. I think LIFO is fine but we do need to remove sockets from the free list when they timeout (which we currently don't). I'm unsure whether LIFO or FIFO is better here... Also, this might be a good idea to apply when the free list is full, i.e. instead of throwing away the most recent socket (as we currently do), we should throw away the least recently used. |
rustyconover
commented
Jan 27, 2020
Why would we want to remove then until we actually try them? That's the current behavior. You have a good idea on the second part about what should be thrown away, updated commit pending. |
ronag
commented
Jan 27, 2020
Because they have timed out. I don't think that's the current behavior? |
rustyconover
commented
Jan 27, 2020
Are there event handlers still reading from the socket once they are placed in the agent pool? I don't believe so. If there aren't any handlers waiting to read how will the code know the socket has timed out? |
ronag
commented
Jan 27, 2020
By adding a handler. See, #23752. |
Uh oh!
There was an error while loading. Please reload this page.
| this.maxFreeSockets > 0 && | ||
| count <= this.maxSockets) { | ||
| if (freeLen >= this.maxFreeSockets) { | ||
| const oldest = this.freeSockets[name].shift(); |
| if (freeLen >= this.maxFreeSockets) { | ||
| const oldest = this.freeSockets[name].shift(); | ||
| oldest.destroy(); | ||
| } else { |
There was a problem hiding this comment.
I'm not quite following, could you explain a bit more.
There was a problem hiding this comment.
the block inside of the else is for the case when !freeSockets, could be simplified
ronag
commented
Jan 27, 2020
Would be nice if you could make a test for this. |
jasnell
commented
Jan 27, 2020
Defensively marking this semver-major for now. It's possible this wouldn't break anyone but we need to verify. |
jasnell
commented
Jan 27, 2020
Ping @nodejs/http |
Trott
commented
Jan 28, 2020
A benchmark would be good. We might already have a relevant benchmark. I'm not sure.
At least in theory, isn't this an implementation detail the user need not worry about? (But I wouldn't oppose a test either. Just not sure if it's necessary.) |
ronag
commented
Jan 28, 2020
Agreed. Nice to have. |
Sockets are added to the free list with .push() but they were being removed with .shift(). This meant the sockets where being removed in FIFO order, but this changes it to LIFO. Since older sockets may be closed based due to inactivity on the server it is more likely that a socket that is recently used will be able to successfully process the next request. Rather than destroying the last used socket destroy the oldest socket in the free list in push() on the last recently used socket.
4ef4a2d to
5af8b39Comparerustyconover
commented
Feb 26, 2020
Trott
commented
Feb 27, 2020
Although there's some ambiguity around the /ping @nodejs/tsc Please review! (@jasnell described marking this as |
mcollina
left a comment
There was a problem hiding this comment.
I would like to have a test for this behavior.
mcollina
commented
Feb 27, 2020
Very good work. This is one of the main changes I did in https://github.com/mcollina/undici to improve the handling of keep-alive connections. |
ronag
commented
Feb 27, 2020
There is a related issue to this that we might want to consider before landing this. We have a problem with sockets in the freelist that timeout are not removed from the list. This change might make that worse, since the least recently used socket is less likely to be used and thus timeout, then when it is actually used the request using it would fail. |
rustyconover
commented
Feb 28, 2020
@ronag Does this mean that the request isn't retried on another connection automatically or is the request simply failed with a connection reset error? |
rustyconover
commented
Feb 28, 2020
@ronag is there a test case that stresses this condition? |
If the user doesn't abort the request in a
Nope, would be nice to have a tests for it. |
ronag
commented
Feb 28, 2020
Just to clarify, I believe my concern is already a problem, however this PR might make it worse. |
@rustyconover: I openend a separate PR to address my concern. I think this PR is good as is once a test is added, though I would prefer to wait for #32000 to land before landing this. |
rustyconover
commented
Feb 29, 2020
@ronag I just wrote a test for the LIFO behavior of this PR. Let me know what you think. |
rustyconover
commented
Feb 29, 2020
@mcollina I just added a test. |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Add a test that ensures the HTTP agent reuses sockets in a LIFO fashion rather than FIFO.
9aad728 to
b43479fComparerustyconover
commented
Mar 1, 2020
@mcollina I believe I've addressed your suggestions in the updated commits. Please let me know what you think. Thank you! 🙏 |
ronag
commented
Mar 11, 2020
@rustyconover this has conflicts |
mcollina
commented
May 20, 2020
Implemented in #33278 |
rustyconover
commented
May 20, 2020
Great! 👍 |
Sockets are added to the free list with .push() but they were
being removed with .shift(). This meant the sockets where being
removed in FIFO order, but this changes it to LIFO. Since older
sockets may be closed based due to inactivity on the server it is
more likely that a socket that is recently used will be able to
successfully process the next request.
make -j4 test(UNIX), orvcbuild test(Windows) passes