Merge pull request #654 from tiborvass/fix-flightcontrol-stack-overflow

flightcontrol: add exponential backoff to Group.Do
docker-18.09
Tõnis Tiigi 2018-10-03 11:35:44 -07:00 committed by GitHub
commit 609c257d62
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 25 additions and 6 deletions

View File

@ -15,7 +15,10 @@ import (
// flightcontrol is like singleflight but with support for cancellation and // flightcontrol is like singleflight but with support for cancellation and
// nested progress reporting // nested progress reporting
var errRetry = errors.Errorf("retry") var (
errRetry = errors.Errorf("retry")
errRetryTimeout = errors.Errorf("exceeded retry timeout")
)
type contextKeyT string type contextKeyT string
@ -29,12 +32,28 @@ type Group struct {
// Do executes a context function syncronized by the key // Do executes a context function syncronized by the key
func (g *Group) Do(ctx context.Context, key string, fn func(ctx context.Context) (interface{}, error)) (v interface{}, err error) { func (g *Group) Do(ctx context.Context, key string, fn func(ctx context.Context) (interface{}, error)) (v interface{}, err error) {
defer func() { var backoff time.Duration
if errors.Cause(err) == errRetry { for {
runtime.Gosched() v, err = g.do(ctx, key, fn)
v, err = g.Do(ctx, key, fn) if err == nil || errors.Cause(err) != errRetry {
return v, err
} }
}() // backoff logic
if backoff >= 3*time.Second {
err = errors.Wrapf(errRetryTimeout, "flightcontrol")
return v, err
}
runtime.Gosched()
if backoff > 0 {
time.Sleep(backoff)
backoff *= 2
} else {
backoff = time.Millisecond
}
}
}
func (g *Group) do(ctx context.Context, key string, fn func(ctx context.Context) (interface{}, error)) (interface{}, error) {
g.mu.Lock() g.mu.Lock()
if g.m == nil { if g.m == nil {
g.m = make(map[string]*call) g.m = make(map[string]*call)