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: Add noDelay to http.request() options. #31539

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

rustyconover
Copy link
Contributor

Add the noDelay option to the http.request() options such that
.setNoDelay() will be called once a socket is obtained.

  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • documentation is changed or added
  • commit message follows commit guidelines

@nodejs-github-bot nodejs-github-bot added the http Issues or PRs related to the http subsystem. label Jan 27, 2020
@sam-github
Copy link
Contributor

Hi, what is the purpose of this?

Default is no delay is true (so nagle is off).

Is there any time you would want nagle on for HTTP? I can't think of one.

Is there any way that http.request() would somehow get a net Socket that had nagle turned on still? I can't think of one, but I might be missing some corner case.

@rustyconover
Copy link
Contributor Author

rustyconover commented Jan 27, 2020

@sam-github Hi, I'm sure your tone is nice and friendly but others might interpret it as a bit aggressive and unwelcoming asking what the purpose is. I think the patch is quite clear in its purpose.

By default tcp sockets are created with the Nagle's delay algorithm enabled. See https://en.wikipedia.org/wiki/Nagle%27s_algorithm. Would you be kind enough to show where you think the default disabling of TCP_NODELAY being set?

That call isn't happening in the strace output that I have of my simple test cases making a request via both HTTPS and HTTP in against node HEAD.

@richardlau
Copy link
Member

re. TCP_NODELAY I don't think we ever did implement #906.

@sam-github
Copy link
Contributor

My apologies @rustyconover, I don't mean to discourage you. Your description was quite clear in the what, but if you look at it again, you will notice that it does not say anything about why, and it is difficult to review a PR without understanding what goal it achieves.

Would you be kind enough to show where you think the default disabling of TCP_NODELAY being set?

My assumption was the documentation was correct, though given the conversation @richardlau linked to, it seems it is not. :-(

@rustyconover
Copy link
Contributor Author

@sam-github It is all good.

My goal is to allow people to control disabling the delay in HTTP options rather than forcing users to call .setNoDelay() on each connection after the fact. It is quite difficult in some code that only takes high-level HTTP options (such as the AWS SDK) to get them to surface the actual request objects that are created so I can disable the Nagle algorithm. Making noDelay available on the HTTP options lets me achieve this goal with the minimum of fussing around.

@rustyconover
Copy link
Contributor Author

@sam-github Also the docs imply the default for the parameter to .setNoDelay() is true if it is not passed, it says nothing about the default for the underlying socket connection when it is created. Should this be made more clear so others don't make the same mistake?

@richardlau
Copy link
Member

@sam-github Also the docs imply the default for the parameter to .setNoDelay() is true if it is not passed, it says nothing about the default for the underlying socket connection when it is created. Should this be made more clear so others don't make the same mistake?

I think so. There was a previous attempt at this (#7995) but it stalled out.

@jasnell
Copy link
Member

jasnell commented Jan 27, 2020

While I'm ok with this in general, I think we should (as a separate activity) explore a better model for passing options down to internal dependent components in general. We have this exact kind of problem (passing options down) in multiple areas and we end up dealing with it in one off ways every time.

@juanarbol
Copy link
Member

This is greeeat! It would be nice to cherry pick the stuff from #31541

Copy link
Member

@addaleax addaleax left a comment

Choose a reason for hiding this comment

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

I’m not sure how I feel about this – if you want to set socket options manually, wouldn’t createConnection() be a more sensible place to do this (as this is more concerned with networking and not really with HTTP itself)?

doc/api/http.md Outdated Show resolved Hide resolved
Copy link
Member

@addaleax addaleax left a comment

Choose a reason for hiding this comment

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

After checking, it looks like the net module does not provide an option like this – I think that if we add this to HTTP, we should definitely also add it to net.Socket. But again, it feels to me like this is better kept on the networking side only.

@rustyconover
Copy link
Contributor Author

@addaleax Hi,

I'm happy to add the same functionality to new net.Socket([options]) in a different PR if you think that's reasonable.

I believe having the noDelay option at the HTTP level is ok right now. The reason is a lot of popular high level packages don't expose the underlying network sockets they use to the user but they typically do expose HTTP options. By not having the functionality here to disable Nagle's algorithm, you're asking every user to pass a custom HTTP Agent that would then hook the createConnection() method and call .setNoDelay() on the socket itself. That seems like too much repetitive burden for something that can be accomplished here for them.

By default all TCP connections have Nagle's algorithm enabled, which is less than optimal for HTTP/HTTPS. Until that changes (i.e. Node decides to disable it by default for HTTP/HTTPS) and it seems like this is the best way forward.

I'm interested to know what you think.

@addaleax
Copy link
Member

@rustyconover To be clear, I’m not opposed to having an option like this in HTTP.

However, I’d prefer to have this in net first in order not to create a situation where we have a feature in HTTP that should be implemented in terms of the net option (thus removing orthogonality here).

I’m okay with this waiting for a PR for net first, but as far as I’m concerned you can just add a separate commit to this one.

Add the noDelay option to the http.request() options such that
.setNoDelay() will be called once a socket is obtained.

Add note about noDelay only applying to a TCP socket.
Add the noDelay option to the net.Socket() options such that
.setNoDelay() will be called when a socket is created
@rustyconover
Copy link
Contributor Author

@addaleax I've added the options to net.Socket() as you've requested in a second commit.

@rustyconover
Copy link
Contributor Author

@jasnell can you please add the author-ready tag?

Copy link
Member

@ronag ronag left a comment

Choose a reason for hiding this comment

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

I think this should have some tests.

@voxpelli
Copy link

voxpelli commented Jul 3, 2020

@sam-github @richardlau I have posted a new PR that replaces the closed #906 and again pushes for changing the default behavior to be TCP_NODELAY: #34185

@rustyconover rustyconover requested a review from a team as a code owner August 10, 2020 16:07
@rustyconover rustyconover requested a review from a team August 10, 2020 16:07
Copy link
Member

@mcollina mcollina left a comment

Choose a reason for hiding this comment

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

I think we might want to set this also for tls.

Moreover, we need tests.

@rustyconover
Copy link
Contributor Author

@mcollina I think tests for this feature run the risk of not showing anything interesting as the TCP_DELAY behavior isn't super deterministic between operating systems or even versions of the same operating system.

Do you have an idea of an adequate test plan?

@@ -417,6 +417,9 @@ added: v0.3.4
* `allowHalfOpen` {boolean} Indicates whether half-opened TCP connections
are allowed. See [`net.createServer()`][] and the [`'end'`][] event
for details. **Default:** `false`.
* `noDelay` {boolean} A boolean with which to call [`socket.setNoDelay()`][]
when a socket connection is established. This only applies when the
underlying connection is a TCP socket.
Copy link
Contributor

Choose a reason for hiding this comment

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

Please add default values.

@mcollina
Copy link
Member

Do you have an idea of an adequate test plan?

I would just override the setNoDelay method.

@voxpelli
Copy link

Do you have an idea of an adequate test plan?

I would just override the setNoDelay method.

So basically:

Override the setNoDelay method in two tests – one that ensures it's called when the option is set and one that ensures it isn't when the option isn't set.

That's good enough as far as tests goes?

@mcollina
Copy link
Member

That's good enough as far as tests goes?

I think so, yes.

@aduh95
Copy link
Contributor

aduh95 commented Nov 17, 2020

@rustyconover Do you plan to keep working on this?

@aduh95 aduh95 added the stalled Issues and PRs that are stalled. label Nov 17, 2020
@github-actions
Copy link
Contributor

This issue/PR was marked as stalled, it will be automatically closed in 30 days. If it should remain open, please leave a comment explaining why it should remain open.

@rustyconover
Copy link
Contributor Author

Sure, I think I'll keep at it.

@voxpelli
Copy link

@rustyconover Feels like the tests should be fairly quick to wrap up, need some help or you have time to fix them yourself?

@aduh95 aduh95 removed the stalled Issues and PRs that are stalled. label Nov 17, 2020
@bl-ue
Copy link
Contributor

bl-ue commented Jun 5, 2021

Stalled again.

@mcollina
Copy link
Member

mcollina commented Jun 5, 2021

would you like to pick it up @bl-ue?

@bl-ue
Copy link
Contributor

bl-ue commented Jun 5, 2021

Ah @mcollina, I feel honored by your offer 😁 ❤️, but I'm afraid I've neither the time nor the expertise in this area to continue it :/

@mcollina
Copy link
Member

mcollina commented Jun 5, 2021

@rustyconover are you still interested in pursuing this?

@rustyconover
Copy link
Contributor Author

I'm still interested in landing this...

@voxpelli
Copy link

This isn't a breaking change, right? So it can go out in any minor? So not important to eg. get it into #40119 ?

@mcollina
Copy link
Member

I prefer the option being on the Agent and not on the http.request().

@aduh95 aduh95 added the semver-minor PRs that contain new features and should be released in the next minor version. label Sep 15, 2021
Copy link
Contributor

@aduh95 aduh95 left a comment

Choose a reason for hiding this comment

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

Can you please add YAML entries similar to

node/doc/api/net.md

Lines 545 to 548 in 6fdd582

changes:
- version: v15.14.0
pr-url: https://github.com/nodejs/node/pull/37735
description: AbortSignal support was added.

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. semver-minor PRs that contain new features and should be released in the next minor version.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet