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

rpc: Make HTTP server timeout values configurable #17240

Merged
merged 7 commits into from
Jul 31, 2018

Conversation

ryanschneider
Copy link
Contributor

This is a fix for #17219 and is an alternative to #17088

In my opinion, whatever timeouts are decided on will not work for everyone, as individual use cases for geth vary substantially. So, this exposes the RPC HTTP timeouts as command line/toml options:

  --rpcreadtimeout value   HTTP-RPC server read timeout (default: 5s)
  --rpcwritetimeout value  HTTP-RPC server write timeout (default: 10s)
  --rpcidletimeout value   HTTP-RPC server idle timeout (default: 2m0s)
[Node.HTTPTimeouts]
ReadTimeout = 5000000000
WriteTimeout = 10000000000
IdleTimeout = 120000000000

Which allows the user to configure their node as best seen fit. With this change I think we can make the defaults more or less aggressive, or keep them where they are.

p.s. I considered a larger refactor where all of the HTTP options are pulled into a separate rpc.HTTPConfig struct in the same way that the P2P options are in P2P p2p.Config. However, that would break existing toml configs so I'd consider that a feature for geth 1.9/2.0.

Copy link
Contributor

@fjl fjl 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 that's a good idea, just a few nitpicks about details ;)

rpc/http.go Outdated
DefaultHTTPIdleTimeout = 120 * time.Second
)

func NewDefaultHTTPTimeouts() HTTPTimeouts {
Copy link
Contributor

Choose a reason for hiding this comment

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

It'd be easier to put the defaults in a global struct variable, e.g. DefaultTimeouts. Then you wouldn't need the constants.

Name: "rpcidletimeout",
Usage: "HTTP-RPC server idle timeout",
Value: rpc.DefaultHTTPIdleTimeout,
}
Copy link
Contributor

Choose a reason for hiding this comment

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

IMHO flags are not needed for this. Very few people will set this option and they can use the config file.

Choose a reason for hiding this comment

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

@fjl the majority of configs can be set from command line so config.toml method is confusing a bit. It would be great to be able to configure this using command line flags.

@ryanschneider
Copy link
Contributor Author

Thanks for the feedback, I should be able to get to these changes today or tomorrow.

But, I just ran into a larger issue I need to debug, in that it seems like the values from the config.toml might be read in correctly. That is, given the config:

[Node.HTTPTimeouts]
ReadTimeout = 60000000000
WriteTimeout = 90000000000
IdleTimeout = 120000000000

[Node.P2P]
MaxPeers = 100

So, change the ReadTimeout to 60s, Wirte to 90s, and MaxPeers to 100, if I run:

geth --config /tmp/geth.toml dumpconfig

The dumped config still has the default timeouts (but but has the correct MaxPeers, which is why I added that as a test case):

#..snip..

[Node.P2P]
MaxPeers = 100
#..snip..

[Node.HTTPTimeouts]
ReadTimeout = 5000000000
WriteTimeout = 10000000000
IdleTimeout = 120000000000

So I need to figure out what's going on there before removing the flag options (I also didn't know flags and config could be mixed, but it appears they can be, so I previously assumed all new features had to be exposed as flags as well).

@ryanschneider
Copy link
Contributor Author

@fjl I've pushed two new commits to address both of the items pointed out by you. And I've pushed a change to the actual defaults to 30s as you requested in #17088.

If you'd prefer I squash all this down to a single commit before accepting let me know and I'll happily do so.

@ryanschneider
Copy link
Contributor Author

Forgot to mention that the issue I ran into was because I was resetting the HTTP timeouts to their defaults in setHTTP when I shouldn't have been; that code was removed as part of the removal of the flags and I verified everything works as expected now.

node/config.go Outdated
@@ -119,6 +120,8 @@ type Config struct {
// exposed.
HTTPModules []string `toml:",omitempty"`

HTTPTimeouts rpc.HTTPTimeouts
Copy link
Member

Choose a reason for hiding this comment

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

Please properly document this field. All other fields are extensively detailed, let's not ruing the streak ;)

rpc/http.go Outdated

func NewDefaultHTTPTimeouts() HTTPTimeouts {
return DefaultHTTPTimeouts
}
Copy link
Member

Choose a reason for hiding this comment

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

There's really no point to have this method here, you can just use rpc.DefaultHTTPTimeouts instead.

rpc/http.go Outdated
IdleTimeout time.Duration
}

var DefaultHTTPTimeouts = HTTPTimeouts{
Copy link
Member

Choose a reason for hiding this comment

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

Please add a doc.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will do!

@ryanschneider
Copy link
Contributor Author

@karalabe & @fjl I believe all requested changes have been completed. Let me know if you want me to squash to a single commit before accepting the PR, happy to do so. If I squash, the commit message would be:

rpc: allow for configuration of RPC HTTP timeouts, increase default Read/WriteTimeout to 30s.

// Wrap the CORS-handler within a host-handler
handler := newCorsHandler(srv, cors)
handler = newVHostHandler(vhosts, handler)

Copy link
Member

@karalabe karalabe Jul 31, 2018

Choose a reason for hiding this comment

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

It would be nice to sanitize the timeout values here. If you use Geth directly, then the code works ok because the defaults are set via CLI flags. If you use go-ethereum as a library however, then this PR is a "breaking" change in its current form because anyone using it needs to specify a new Config field, otherwise the HTTP RPC is bricked due to 0 timeouts.

An elegant solution would be to iterate over the 3 timeout fields here before constructing the http.Server and if any of them is < 1 second (to avoid misused timeouts), reset it to the default:

	if timeouts.ReadTimeout < time.Second {
		log.Warn("Sanitizing invalid HTTP read timeout", "provided", timeouts.ReadTimeout, "updated", DefaultHTTPTimeouts.ReadTimeout)
		timeouts.ReadTimeout = DefaultHTTPTimeouts.ReadTimeout
	}
	if timeouts.WriteTimeout < time.Second {
		log.Warn("Sanitizing invalid HTTP write timeout", "provided", timeouts.WriteTimeout, "updated", DefaultHTTPTimeouts.WriteTimeout)
		timeouts.WriteTimeout = DefaultHTTPTimeouts.WriteTimeout
	}
	if timeouts.IdleTimeout < time.Second {
		log.Warn("Sanitizing invalid HTTP idle timeout", "provided", timeouts.IdleTimeout, "updated", DefaultHTTPTimeouts.IdleTimeout)
		timeouts.IdleTimeout = DefaultHTTPTimeouts.IdleTimeout
	}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I just tested this, and actually it appears that the 0 values work just fine, they just disable the timeouts.

Looking at the Go runtime code, it appears that the HTTP server fully expects 0-valued ReadTimeout/WriteTimeout/IdleTimeout fields, since they are the default for Server{}.

For example see this line in http2/server.go, where the ReadTimeout is only used if non-zero:

https://github.com/golang/net/blob/master/http2/server.go#L1818

So actually, when used as a library, go-ethereum 1.8.13 now behaves like it did pre-18.11, before #16880 was merged, where the server ran without any timeouts whatsoever.

I'm not sure if this is desired behavior or not though, but IMO we should allow 0 as a value in the .toml config, as some users may have a good reason to run without timeouts. For example, the Go runtime does behave slightly differently between a 0 timeout and a very long one, wrt context deadlines and such, so someone might have good reason to truly have a 0 timeout when integrating go-ethereum as a library.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@karalabe oh, when I made the above comment I hadn't realized you'd added the sanitization (I was tested the un-sanitized initial version just to be clear). I'm not sure I agree with needing the sanitization.

@karalabe karalabe force-pushed the rpc-http-timeouts branch from a6604b0 to 254d265 Compare July 31, 2018 09:14
@karalabe karalabe added this to the 1.8.13 milestone Jul 31, 2018
@karalabe karalabe merged commit 5d7e185 into ethereum:master Jul 31, 2018
firmianavan pushed a commit to firmianavan/go-ethereum that referenced this pull request Aug 28, 2018
)

* rpc: Make HTTP server timeout values configurable

* rpc: Remove flags for setting HTTP Timeouts, configuring via .toml is sufficient.

* rpc: Replace separate constants with a single default struct.

* rpc: Update HTTP Server Read and Write Timeouts to 30s.

* rpc: Remove redundant NewDefaultHTTPTimeouts function.

* rpc: document HTTPTimeouts.

* rpc: sanitize timeout values for library use
@Crypto2
Copy link

Crypto2 commented Aug 28, 2018

Is this going to be added? I don't see --rpcidletimeout, etc. in the --help output running 1.8.14? The new timeouts are causing a lot of issues for us like others with sends timing out so you have to do a bunch of blockchain checks since you don't know if the TX sent or not.

@ryanschneider
Copy link
Contributor Author

This functionality is in 1.8.13+.

It was decided that the command line arguments were too cluttered, so the values are only configurable via .toml, see for example geth dumpconfig:

[Node.HTTPTimeouts]
ReadTimeout = 30000000000
WriteTimeout = 30000000000
IdleTimeout = 120000000000

In addition to your other command line args, you can start geth with --config /path/to/config.toml and just include the above in your config.toml and adjust as needed.

As with other time.Duration values in the toml file, the units are nanoseconds.

gzliudan added a commit to gzliudan/XDPoSChain that referenced this pull request Nov 4, 2024
wanwiset25 pushed a commit to XinFinOrg/XDPoSChain that referenced this pull request Nov 13, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants