-
Notifications
You must be signed in to change notification settings - Fork 20.5k
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
Conversation
There was a problem hiding this 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 { |
There was a problem hiding this comment.
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.
cmd/utils/flags.go
Outdated
Name: "rpcidletimeout", | ||
Usage: "HTTP-RPC server idle timeout", | ||
Value: rpc.DefaultHTTPIdleTimeout, | ||
} |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
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:
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). |
Forgot to mention that the issue I ran into was because I was resetting the HTTP timeouts to their defaults in |
node/config.go
Outdated
@@ -119,6 +120,8 @@ type Config struct { | |||
// exposed. | |||
HTTPModules []string `toml:",omitempty"` | |||
|
|||
HTTPTimeouts rpc.HTTPTimeouts |
There was a problem hiding this comment.
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 | ||
} |
There was a problem hiding this comment.
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{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a doc.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do!
@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:
|
// Wrap the CORS-handler within a host-handler | ||
handler := newCorsHandler(srv, cors) | ||
handler = newVHostHandler(vhosts, handler) | ||
|
There was a problem hiding this comment.
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
}
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
a6604b0
to
254d265
Compare
) * 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
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. |
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
In addition to your other command line args, you can start geth with As with other |
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:
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 inP2P p2p.Config
. However, that would break existing toml configs so I'd consider that a feature for geth 1.9/2.0.