Skip to content

Commit bc6db92

Browse files
committed
[FAB-4743] Harden backoff policy code in deliverClient
The delivery client has a backoff policy that specifies an amount of time to sleep and whether to continue to retry based on an attempt number. Currently the code that calculates the amount of time to sleep is prone to overflow to a negative number. However, the fact that the code only retries a limited number of times (not indefinitely) saves us from the overflow. I would like to make the code that calculates the time duration to sleep to never overflow in order for if someone in the future to change the attempt threshold and forget about the overflow problem lurking around the corner, we won't have a problem. Change-Id: Ie0d365e879eb71141c278231819e52e341b73fe5 Signed-off-by: Yacov Manevich <[email protected]>
1 parent 4dc0370 commit bc6db92

File tree

2 files changed

+19
-1
lines changed

2 files changed

+19
-1
lines changed

core/deliverservice/deliveryclient.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ func init() {
3131
var (
3232
reConnectTotalTimeThreshold = time.Second * 60 * 5
3333
connTimeout = time.Second * 3
34+
reConnectBackoffThreshold = float64(time.Hour)
3435
)
3536

3637
// DeliverService used to communicate with orderers to obtain
@@ -181,7 +182,9 @@ func (d *deliverServiceImpl) newClient(chainID string, ledgerInfoProvider blocks
181182
if elapsedTime.Nanoseconds() > reConnectTotalTimeThreshold.Nanoseconds() {
182183
return 0, false
183184
}
184-
return time.Duration(math.Pow(2, float64(attemptNum))) * time.Millisecond * 500, true
185+
sleepIncrement := float64(time.Millisecond * 500)
186+
attempt := float64(attemptNum)
187+
return time.Duration(math.Min(math.Pow(2, attempt)*sleepIncrement, reConnectBackoffThreshold)), true
185188
}
186189
connProd := comm.NewConnectionProducer(d.conf.ConnFactory(chainID), d.conf.Endpoints)
187190
bClient := NewBroadcastClient(connProd, d.conf.ABCFactory, broadcastSetup, backoffPolicy)

core/deliverservice/deliveryclient_test.go

+15
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package deliverclient
1818

1919
import (
20+
"errors"
2021
"runtime"
2122
"sync"
2223
"sync/atomic"
@@ -406,6 +407,20 @@ func TestDeliverServiceBadConfig(t *testing.T) {
406407
assert.Nil(t, service)
407408
}
408409

410+
func TestRetryPolicyOverflow(t *testing.T) {
411+
connFactory := func(channelID string) func(endpoint string) (*grpc.ClientConn, error) {
412+
return func(_ string) (*grpc.ClientConn, error) {
413+
return nil, errors.New("")
414+
}
415+
}
416+
client := (&deliverServiceImpl{conf: &Config{ConnFactory: connFactory}}).newClient("TEST", &mocks.MockLedgerInfo{Height: uint64(100)})
417+
assert.NotNil(t, client.shouldRetry)
418+
for i := 0; i < 100; i++ {
419+
retryTime, _ := client.shouldRetry(i, time.Second)
420+
assert.True(t, retryTime <= time.Hour && retryTime > 0)
421+
}
422+
}
423+
409424
func assertBlockDissemination(expectedSeq uint64, ch chan uint64, t *testing.T) {
410425
select {
411426
case seq := <-ch:

0 commit comments

Comments
 (0)