Merge pull request #1358 from pulumi/retry-bugs

Fix two bugs in retries
This commit is contained in:
Matthew Riley 2018-06-01 17:11:23 -07:00 committed by GitHub
commit 261fa86586
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 17 additions and 17 deletions

View file

@ -19,6 +19,7 @@ import (
"net/http" "net/http"
"time" "time"
"github.com/pulumi/pulumi/pkg/util/contract"
"github.com/pulumi/pulumi/pkg/util/retry" "github.com/pulumi/pulumi/pkg/util/retry"
) )
@ -40,6 +41,11 @@ func DoWithRetry(req *http.Request, client *http.Client) (*http.Response, error)
if try >= (maxRetryCount - 1) { if try >= (maxRetryCount - 1) {
return false, res, resErr return false, res, resErr
} }
// Close the response body, if present, since our caller can't.
if resErr == nil {
contract.IgnoreError(res.Body.Close())
}
return false, nil, nil return false, nil, nil
}, },
}) })

View file

@ -41,8 +41,6 @@ const (
// return boolean of true means the acceptor eventually accepted; a non-nil error means the acceptor returned an error. // return boolean of true means the acceptor eventually accepted; a non-nil error means the acceptor returned an error.
// If an acceptor accepts a condition after the context has expired, we ignore the expiration and return the condition. // If an acceptor accepts a condition after the context has expired, we ignore the expiration and return the condition.
func Until(ctx context.Context, acceptor Acceptor) (bool, interface{}, error) { func Until(ctx context.Context, acceptor Acceptor) (bool, interface{}, error) {
expired := false
// Prepare our delay and backoff variables. // Prepare our delay and backoff variables.
var delay time.Duration var delay time.Duration
if acceptor.Delay == nil { if acceptor.Delay == nil {
@ -63,17 +61,9 @@ func Until(ctx context.Context, acceptor Acceptor) (bool, interface{}, error) {
maxDelay = *acceptor.MaxDelay maxDelay = *acceptor.MaxDelay
} }
// If the context expires before the waiter has accepted, return. // Loop until the condition is accepted or the context expires, whichever comes first.
if ctx != nil { try := 0
go func() { for {
<-ctx.Done()
expired = true
}()
}
// Loop until the condition is accepted, or the context expires, whichever comes first.
var try int
for !expired {
// Compute the next retry time so the callback can access it. // Compute the next retry time so the callback can access it.
delay = time.Duration(float64(delay) * backoff) delay = time.Duration(float64(delay) * backoff)
if delay > maxDelay { if delay > maxDelay {
@ -86,12 +76,16 @@ func Until(ctx context.Context, acceptor Acceptor) (bool, interface{}, error) {
return b, data, err return b, data, err
} }
// About to try again. Sleep, bump the retry count, and go around the horn again. // Wait for delay or timeout.
time.Sleep(delay) select {
case <-time.After(delay):
// Continue on.
case <-ctx.Done():
return false, nil, nil
}
try++ try++
} }
return false, nil, nil
} }
// UntilDeadline creates a child context with the given deadline, and then invokes the above Until function. // UntilDeadline creates a child context with the given deadline, and then invokes the above Until function.