Skip to content

Commit d95ed2c

Browse files
committed
various context related cleanups to rest.Request
* Move all usage of r.ctx to the beginning of Do, DoRaw, Stream, Watch * Move tryThrottle from Do and DoRaw into request() * Make request() and tryThrottle take a context * In request(), remove the timeout context setting out of the loop These changes should be entirely behavior preserving.
1 parent e2f529a commit d95ed2c

File tree

1 file changed

+40
-33
lines changed

1 file changed

+40
-33
lines changed

staging/src/k8s.io/client-go/rest/request.go

Lines changed: 40 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -548,18 +548,14 @@ func (r Request) finalURLTemplate() url.URL {
548548
return *url
549549
}
550550

551-
func (r *Request) tryThrottle() error {
551+
func (r *Request) tryThrottle(ctx context.Context) error {
552552
if r.rateLimiter == nil {
553553
return nil
554554
}
555555

556556
now := time.Now()
557-
var err error
558-
if r.ctx != nil {
559-
err = r.rateLimiter.Wait(r.ctx)
560-
} else {
561-
r.rateLimiter.Accept()
562-
}
557+
558+
err := r.rateLimiter.Wait(ctx)
563559

564560
if latency := time.Since(now); latency > longThrottleLatency {
565561
klog.V(3).Infof("Throttling request took %v, request: %s:%s", latency, r.verb, r.URL().String())
@@ -571,6 +567,11 @@ func (r *Request) tryThrottle() error {
571567
// Watch attempts to begin watching the requested location.
572568
// Returns a watch.Interface, or an error.
573569
func (r *Request) Watch() (watch.Interface, error) {
570+
ctx := context.Background()
571+
if r.ctx != nil {
572+
ctx = r.ctx
573+
}
574+
574575
// We specifically don't want to rate limit watches, so we
575576
// don't use r.rateLimiter here.
576577
if r.err != nil {
@@ -582,9 +583,7 @@ func (r *Request) Watch() (watch.Interface, error) {
582583
if err != nil {
583584
return nil, err
584585
}
585-
if r.ctx != nil {
586-
req = req.WithContext(r.ctx)
587-
}
586+
req = req.WithContext(ctx)
588587
req.Header = r.headers
589588
client := r.c.Client
590589
if client == nil {
@@ -660,11 +659,16 @@ func updateURLMetrics(req *Request, resp *http.Response, err error) {
660659
// Any non-2xx http status code causes an error. If we get a non-2xx code, we try to convert the body into an APIStatus object.
661660
// If we can, we return that as an error. Otherwise, we create an error that lists the http status and the content of the response.
662661
func (r *Request) Stream() (io.ReadCloser, error) {
662+
ctx := context.Background()
663+
if r.ctx != nil {
664+
ctx = r.ctx
665+
}
666+
663667
if r.err != nil {
664668
return nil, r.err
665669
}
666670

667-
if err := r.tryThrottle(); err != nil {
671+
if err := r.tryThrottle(ctx); err != nil {
668672
return nil, err
669673
}
670674

@@ -676,9 +680,7 @@ func (r *Request) Stream() (io.ReadCloser, error) {
676680
if r.body != nil {
677681
req.Body = ioutil.NopCloser(r.body)
678682
}
679-
if r.ctx != nil {
680-
req = req.WithContext(r.ctx)
681-
}
683+
req = req.WithContext(ctx)
682684
req.Header = r.headers
683685
client := r.c.Client
684686
if client == nil {
@@ -746,7 +748,7 @@ func (r *Request) requestPreflightCheck() error {
746748
// received. It handles retry behavior and up front validation of requests. It will invoke
747749
// fn at most once. It will return an error if a problem occurred prior to connecting to the
748750
// server - the provided function is responsible for handling server errors.
749-
func (r *Request) request(fn func(*http.Request, *http.Response)) error {
751+
func (r *Request) request(ctx context.Context, fn func(*http.Request, *http.Response)) error {
750752
//Metrics for total request latency
751753
start := time.Now()
752754
defer func() {
@@ -767,6 +769,19 @@ func (r *Request) request(fn func(*http.Request, *http.Response)) error {
767769
client = http.DefaultClient
768770
}
769771

772+
// Throttle the first try before setting up the timeout configured on the
773+
// client. We don't want a throttled client to return timeouts to callers
774+
// before it makes a single request.
775+
if err := r.tryThrottle(ctx); err != nil {
776+
return err
777+
}
778+
779+
if r.timeout > 0 {
780+
var cancel context.CancelFunc
781+
ctx, cancel = context.WithTimeout(ctx, r.timeout)
782+
defer cancel()
783+
}
784+
770785
// Right now we make about ten retry attempts if we get a Retry-After response.
771786
maxRetries := 10
772787
retries := 0
@@ -776,25 +791,15 @@ func (r *Request) request(fn func(*http.Request, *http.Response)) error {
776791
if err != nil {
777792
return err
778793
}
779-
if r.timeout > 0 {
780-
if r.ctx == nil {
781-
r.ctx = context.Background()
782-
}
783-
var cancelFn context.CancelFunc
784-
r.ctx, cancelFn = context.WithTimeout(r.ctx, r.timeout)
785-
defer cancelFn()
786-
}
787-
if r.ctx != nil {
788-
req = req.WithContext(r.ctx)
789-
}
794+
req = req.WithContext(ctx)
790795
req.Header = r.headers
791796

792797
r.backoff.Sleep(r.backoff.CalculateBackoff(r.URL()))
793798
if retries > 0 {
794799
// We are retrying the request that we already send to apiserver
795800
// at least once before.
796801
// This request should also be throttled with the client-internal rate limiter.
797-
if err := r.tryThrottle(); err != nil {
802+
if err := r.tryThrottle(ctx); err != nil {
798803
return err
799804
}
800805
}
@@ -870,12 +875,13 @@ func (r *Request) request(fn func(*http.Request, *http.Response)) error {
870875
// * If the server responds with a status: *errors.StatusError or *errors.UnexpectedObjectError
871876
// * http.Client.Do errors are returned directly.
872877
func (r *Request) Do() Result {
873-
if err := r.tryThrottle(); err != nil {
874-
return Result{err: err}
878+
ctx := context.Background()
879+
if r.ctx != nil {
880+
ctx = r.ctx
875881
}
876882

877883
var result Result
878-
err := r.request(func(req *http.Request, resp *http.Response) {
884+
err := r.request(ctx, func(req *http.Request, resp *http.Response) {
879885
result = r.transformResponse(resp, req)
880886
})
881887
if err != nil {
@@ -886,12 +892,13 @@ func (r *Request) Do() Result {
886892

887893
// DoRaw executes the request but does not process the response body.
888894
func (r *Request) DoRaw() ([]byte, error) {
889-
if err := r.tryThrottle(); err != nil {
890-
return nil, err
895+
ctx := context.Background()
896+
if r.ctx != nil {
897+
ctx = r.ctx
891898
}
892899

893900
var result Result
894-
err := r.request(func(req *http.Request, resp *http.Response) {
901+
err := r.request(ctx, func(req *http.Request, resp *http.Response) {
895902
result.body, result.err = ioutil.ReadAll(resp.Body)
896903
glogBody("Response Body", result.body)
897904
if resp.StatusCode < http.StatusOK || resp.StatusCode > http.StatusPartialContent {

0 commit comments

Comments
 (0)