fix: really cap the max backoff at 10 minutes
While preserving some randomness. And add a test.
Steven Allen committed
May 25, 2020 at 21:18 UTC
e10289a93d50e3cc80a5a3692b98391cc1aab62b
2 files changed
+35
-2
peering/peering.go
+16
-2
@@ -14,10 +14,17 @@ import (
14
"github.com/multiformats/go-multiaddr"
15
)
16
17
+// Seed the random number generator.
18
+//
19
+// We don't need good randomness, but we do need randomness.
20
const (
21
// maxBackoff is the maximum time between reconnect attempts.
22
maxBackoff = 10 * time.Minute
20
- connmgrTag = "ipfs-peering"
23
+ // The backoff will be cut off when we get within 10% of the actual max.
24
+ // If we go over the max, we'll adjust the delay down to a random value
25
+ // between 90-100% of the max backoff.
26
+ maxBackoffJitter = 10 // %
27
+ connmgrTag = "ipfs-peering"
28
// This needs to be sufficient to prevent two sides from simultaneously
29
// dialing.
30
initialDelay = 5 * time.Second
@@ -78,10 +85,17 @@ func (ph *peerHandler) stop() {
85
}
86
87
func (ph *peerHandler) nextBackoff() time.Duration {
81
- // calculate the timeout
88
if ph.nextDelay < maxBackoff {
89
ph.nextDelay += ph.nextDelay/2 + time.Duration(rand.Int63n(int64(ph.nextDelay)))
90
}
91
+
92
+ // If we've gone over the max backoff, reduce it under the max.
93
+ if ph.nextDelay > maxBackoff {
94
+ ph.nextDelay = maxBackoff
95
+ // randomize the backoff a bit (10%).
96
+ ph.nextDelay -= time.Duration(rand.Int63n(int64(maxBackoff) * maxBackoffJitter / 100))
97
+ }
98
+
99
return ph.nextDelay
100
}
101
peering/peering_test.go
+19
@@ -137,3 +137,22 @@ func TestPeeringService(t *testing.T) {
137
ps1.AddPeer(peer.AddrInfo{ID: h4.ID(), Addrs: h4.Addrs()})
138
ps1.RemovePeer(h2.ID())
139
}
140
+
141
+func TestNextBackoff(t *testing.T) {
142
+ minMaxBackoff := (100 - maxBackoffJitter) / 100 * maxBackoff
143
+ for x := 0; x < 1000; x++ {
144
+ ph := peerHandler{nextDelay: time.Second}
145
+ for min, max := time.Second*3/2, time.Second*5/2; min < minMaxBackoff; min, max = min*3/2, max*5/2 {
146
+ b := ph.nextBackoff()
147
+ if b > max || b < min {
148
+ t.Errorf("expected backoff %s to be between %s and %s", b, min, max)
149
+ }
150
+ }
151
+ for i := 0; i < 100; i++ {
152
+ b := ph.nextBackoff()
153
+ if b < minMaxBackoff || b > maxBackoff {
154
+ t.Fatal("failed to stay within max bounds")
155
+ }
156
+ }
157
+ }
158
+}