Skip to content

Commit

Permalink
fix: really cap the max backoff at 10 minutes
Browse files Browse the repository at this point in the history
While preserving some randomness.

And add a test.
  • Loading branch information
Stebalien committed May 26, 2020
1 parent 17b3b02 commit e10289a
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 2 deletions.
18 changes: 16 additions & 2 deletions peering/peering.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,17 @@ import (
"github.com/multiformats/go-multiaddr"
)

// Seed the random number generator.
//
// We don't need good randomness, but we do need randomness.
const (
// maxBackoff is the maximum time between reconnect attempts.
maxBackoff = 10 * time.Minute
connmgrTag = "ipfs-peering"
// The backoff will be cut off when we get within 10% of the actual max.
// If we go over the max, we'll adjust the delay down to a random value
// between 90-100% of the max backoff.
maxBackoffJitter = 10 // %
connmgrTag = "ipfs-peering"
// This needs to be sufficient to prevent two sides from simultaneously
// dialing.
initialDelay = 5 * time.Second
Expand Down Expand Up @@ -78,10 +85,17 @@ func (ph *peerHandler) stop() {
}

func (ph *peerHandler) nextBackoff() time.Duration {
// calculate the timeout
if ph.nextDelay < maxBackoff {
ph.nextDelay += ph.nextDelay/2 + time.Duration(rand.Int63n(int64(ph.nextDelay)))
}

// If we've gone over the max backoff, reduce it under the max.
if ph.nextDelay > maxBackoff {
ph.nextDelay = maxBackoff
// randomize the backoff a bit (10%).
ph.nextDelay -= time.Duration(rand.Int63n(int64(maxBackoff) * maxBackoffJitter / 100))
}

return ph.nextDelay
}

Expand Down
19 changes: 19 additions & 0 deletions peering/peering_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,3 +137,22 @@ func TestPeeringService(t *testing.T) {
ps1.AddPeer(peer.AddrInfo{ID: h4.ID(), Addrs: h4.Addrs()})
ps1.RemovePeer(h2.ID())
}

func TestNextBackoff(t *testing.T) {
minMaxBackoff := (100 - maxBackoffJitter) / 100 * maxBackoff
for x := 0; x < 1000; x++ {
ph := peerHandler{nextDelay: time.Second}
for min, max := time.Second*3/2, time.Second*5/2; min < minMaxBackoff; min, max = min*3/2, max*5/2 {
b := ph.nextBackoff()
if b > max || b < min {
t.Errorf("expected backoff %s to be between %s and %s", b, min, max)
}
}
for i := 0; i < 100; i++ {
b := ph.nextBackoff()
if b < minMaxBackoff || b > maxBackoff {
t.Fatal("failed to stay within max bounds")
}
}
}
}

0 comments on commit e10289a

Please sign in to comment.