-
Notifications
You must be signed in to change notification settings - Fork 40k
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
client-go: changes config.Timeout field semantic #101022
client-go: changes config.Timeout field semantic #101022
Conversation
@p0lyn0mial: Adding the "do-not-merge/release-note-label-needed" label because no release-note block was detected, please follow our release note process to remove it. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
42c4516
to
db930d6
Compare
} | ||
|
||
// NewRESTClient creates a new RESTClient. This client performs generic REST functions | ||
// such as Get, Put, Post, and Delete on specified paths. | ||
func NewRESTClient(baseURL *url.URL, versionedAPIPath string, config ClientContentConfig, rateLimiter flowcontrol.RateLimiter, client *http.Client) (*RESTClient, error) { | ||
func NewRESTClient(baseURL *url.URL, versionedAPIPath string, config ClientContentConfig, rateLimiter flowcontrol.RateLimiter, client *http.Client, requestTimeout time.Duration) (*RESTClient, error) { |
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.
worth to avoid a breaking change through NewRESTClientWithTimeout
?
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.
How many clients of this method do we have?
I didn't have to fix many references, just two.
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.
Since client-go is a library, this change affects non k/k code as well.
@@ -100,11 +100,14 @@ type RESTClient struct { | |||
|
|||
// Set specific behavior of the client. If not set http.DefaultClient will be used. | |||
Client *http.Client | |||
|
|||
// RequestTimeout specifies a time limit for requests made by the HTTP Client | |||
RequestTimeout time.Duration |
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.
does this have to be public?
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.
no, I don't think so. Will change to private.
|
||
// validate | ||
if len(res) > failedProbesTreshold { | ||
t.Fatalf("%d%% of probes failed. That means some (all) watch requests ended sooner than we expected. The current treshold was set to %d%%"+ |
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.
this message might look like this:
100% of probes failed. That means some (all) watch requests ended sooner than we expected. The current treshold was set to 33% We did 6 probes in total. The upper-bound time limit for a single watch reqeust was set to 11s. 6 probes ended before that time [10.000410361s 10.001010468s 10.000472694s 10.001261837s 10.002812845s 10.001133277s]
If this PR turns out to be viable then we don't need #100959 |
db930d6
to
fd1bd1e
Compare
/retest |
@@ -324,9 +324,12 @@ func RESTClientFor(config *Config) (*RESTClient, error) { | |||
var httpClient *http.Client | |||
if transport != http.DefaultTransport { | |||
httpClient = &http.Client{Transport: transport} | |||
if config.Timeout > 0 { | |||
httpClient.Timeout = config.Timeout |
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.
With this removed, how do I create a rest.Config that has a client-side, context based timeout on every request? I was fairly sure this was exactly the right spot to set up such a timeout.
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.
how do I create a rest.Config that has a client-side, context based timeout on every request?
In exactly the same way as before. This behavior hasn't changed.
A global timeout, per client, enforced client-side, seems very reasonable to me and matches what the existing code does. The current problem we face appears to be using a client with an explicitly configured, client-enforced timeout for a request we don't want to have the timeout enforced on. This appears to be an "us" problem, not a client problem. Why wouldn't the delegating authenticator simply create the client with the configuration it wants? Clearly it does not want watches terminating every 10 seconds. |
This PR sets a global, per client timeout too. That behaviour hasn't changed.
It seems that the current problem we face is that the timeout for watch request is not respected at all.
I think that it would be good if the delegating authenticator could set a short timeout for |
httpClient.Timeout = config.Timeout | ||
} | ||
// do not set a timeout on the http client, instead use context for cancellation | ||
// if multiple timeouts were set, the request will pick the smaller timeout to be applied, leaving other useless. |
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.
if multiple timeouts were set, the request will pick the smaller timeout to be applied, leaving other useless
if multiple timeouts were set, I would expect the smallest to rule
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.
if this is what we want for client-go then sure. As it is today sharing the same client for normal requests and informers and setting a conig.Timeout
to 10 seconds
will terminate watches created by informers every 10 seconds
.
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.
You should not have to create two clients to use an informer. client-go should let you specifically set a timeout for long running requests distinct from normal requests, and it should be clear what it does.
dd98be3
to
b010fa5
Compare
/remove-sig auth |
@p0lyn0mial: PR needs rebase. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. |
The Kubernetes project currently lacks enough contributors to adequately respond to all issues and PRs. This bot triages issues and PRs according to the following rules:
You can:
Please send feedback to sig-contributor-experience at kubernetes/community. /lifecycle stale |
/remove-lifecycle stal |
/cc |
The Kubernetes project currently lacks enough active contributors to adequately respond to all issues and PRs. This bot triages issues and PRs according to the following rules:
You can:
Please send feedback to sig-contributor-experience at kubernetes/community. /lifecycle rotten |
/remove-lifecycle rotten |
Is this PR still needed, please rebase if so (or we can close it?) |
/unassign |
closing due to inactivity |
What type of PR is this?
/kind bug
What this PR does / why we need it:
This PR uses context for cancellation instead of setting a timeout on the HTTP client.
It turns out that setting a timeout on HTTP client affect watch requests.
For example, with a 10 second timeout watch requests are being re-established exactly after 10 seconds even though the default request timeout for them is ~5 minutes (informers).
This is because if multiple timeouts were set, the stdlib picks the smaller timeout to be applied, leaving other useless.
For more details see https://github.com/golang/go/blob/a937729c2c2f6950a32bc5cd0f5b88700882f078/src/net/http/client.go#L364
This PR preserves the previous behavior for all requests except the watch requests. With this PR a timeout set by
ListOptions
on watches is respected - used heavily by the informers. In particular when a global timeout viaconfig.Timeout
was set and no other timeout was specified then watch requests will be terminated afterconfig.Timeout
, just like before.Which issue(s) this PR fixes:
Fixes #
Special notes for your reviewer:
Does this PR introduce a user-facing change?
Additional documentation e.g., KEPs (Kubernetes Enhancement Proposals), usage docs, etc.: