Merge branch 'master' of https://github.com/grpc/grpc-go
This commit is contained in:
@ -55,6 +55,8 @@ var (
|
||||
// ErrClientConnTimeout indicates that the connection could not be
|
||||
// established or re-established within the specified timeout.
|
||||
ErrClientConnTimeout = errors.New("grpc: timed out trying to connect")
|
||||
// minimum time to give a connection to complete
|
||||
minConnectTimeout = 20 * time.Second
|
||||
)
|
||||
|
||||
// dialOptions configure a Dial call. dialOptions are set by the DialOption
|
||||
@ -211,9 +213,21 @@ func (cc *ClientConn) resetTransport(closeTransport bool) error {
|
||||
return ErrClientConnTimeout
|
||||
}
|
||||
}
|
||||
sleepTime := backoff(retries)
|
||||
timeout := sleepTime
|
||||
if timeout < minConnectTimeout {
|
||||
timeout = minConnectTimeout
|
||||
}
|
||||
if copts.Timeout == 0 || copts.Timeout > timeout {
|
||||
copts.Timeout = timeout
|
||||
}
|
||||
connectTime := time.Now()
|
||||
newTransport, err := transport.NewClientTransport(cc.target, &copts)
|
||||
if err != nil {
|
||||
sleepTime := backoff(retries)
|
||||
sleepTime -= time.Since(connectTime)
|
||||
if sleepTime < 0 {
|
||||
sleepTime = 0
|
||||
}
|
||||
// Fail early before falling into sleep.
|
||||
if cc.dopts.copts.Timeout > 0 && cc.dopts.copts.Timeout < sleepTime+time.Since(start) {
|
||||
cc.Close()
|
||||
|
25
rpc_util.go
25
rpc_util.go
@ -277,28 +277,29 @@ func convertCode(err error) codes.Code {
|
||||
const (
|
||||
// how long to wait after the first failure before retrying
|
||||
baseDelay = 1.0 * time.Second
|
||||
// upper bound on backoff delay
|
||||
maxDelay = 120 * time.Second
|
||||
backoffFactor = 2.0 // backoff increases by this factor on each retry
|
||||
backoffRange = 0.4 // backoff is randomized downwards by this factor
|
||||
// upper bound of backoff delay
|
||||
maxDelay = 120 * time.Second
|
||||
// backoff increases by this factor on each retry
|
||||
backoffFactor = 1.6
|
||||
// backoff is randomized downwards by this factor
|
||||
backoffJitter = 0.2
|
||||
)
|
||||
|
||||
// backoff returns a value in [0, maxDelay] that increases exponentially with
|
||||
// retries, starting from baseDelay.
|
||||
func backoff(retries int) time.Duration {
|
||||
func backoff(retries int) (t time.Duration) {
|
||||
if retries == 0 {
|
||||
return baseDelay
|
||||
}
|
||||
backoff, max := float64(baseDelay), float64(maxDelay)
|
||||
for backoff < max && retries > 0 {
|
||||
backoff = backoff * backoffFactor
|
||||
backoff *= backoffFactor
|
||||
retries--
|
||||
}
|
||||
if backoff > max {
|
||||
backoff = max
|
||||
}
|
||||
|
||||
// Randomize backoff delays so that if a cluster of requests start at
|
||||
// the same time, they won't operate in lockstep. We just subtract up
|
||||
// to 40% so that we obey maxDelay.
|
||||
backoff -= backoff * backoffRange * rand.Float64()
|
||||
// the same time, they won't operate in lockstep.
|
||||
backoff *= 1 + backoffJitter*(rand.Float64()*2-1)
|
||||
if backoff < 0 {
|
||||
return 0
|
||||
}
|
||||
|
@ -36,10 +36,8 @@ package grpc
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"math"
|
||||
"reflect"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"golang.org/x/net/context"
|
||||
@ -153,25 +151,6 @@ func TestContextErr(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBackoff(t *testing.T) {
|
||||
for _, test := range []struct {
|
||||
retries int
|
||||
maxResult time.Duration
|
||||
}{
|
||||
{0, time.Second},
|
||||
{1, time.Duration(1e9 * math.Pow(backoffFactor, 1))},
|
||||
{2, time.Duration(1e9 * math.Pow(backoffFactor, 2))},
|
||||
{3, time.Duration(1e9 * math.Pow(backoffFactor, 3))},
|
||||
{4, time.Duration(1e9 * math.Pow(backoffFactor, 4))},
|
||||
{int(math.Log2(float64(maxDelay)/float64(baseDelay))) + 1, maxDelay},
|
||||
} {
|
||||
delay := backoff(test.retries)
|
||||
if delay < 0 || delay > test.maxResult {
|
||||
t.Errorf("backoff(%d) = %v outside [0, %v]", test.retries, delay, test.maxResult)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// bmEncode benchmarks encoding a Protocol Buffer message containing mSize
|
||||
// bytes.
|
||||
func bmEncode(b *testing.B, mSize int) {
|
||||
|
@ -555,7 +555,7 @@ func (t *http2Client) handleData(f *http2.DataFrame) {
|
||||
// the read direction is closed, and set the status appropriately.
|
||||
if f.FrameHeader.Flags.Has(http2.FlagDataEndStream) {
|
||||
s.mu.Lock()
|
||||
if (s.state == streamWriteDone) {
|
||||
if s.state == streamWriteDone {
|
||||
s.state = streamDone
|
||||
} else {
|
||||
s.state = streamReadDone
|
||||
|
Reference in New Issue
Block a user