Skip to content

Commit

Permalink
Allow delay / backoff before first connection attempt
Browse files Browse the repository at this point in the history
  • Loading branch information
ViToni committed Aug 9, 2024
1 parent 8c0b228 commit 29212b8
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 9 deletions.
13 changes: 11 additions & 2 deletions autopaho/backoff.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,19 @@ import (
)

// Backoff function to compute backoff duration for the Nth attempt
// attempt starts at "0" indicating the delay BEFORE the first attempt
type Backoff func(attempt int) time.Duration

////////////////////////////////////////////////////////////////////////////////
// implementation for constant backoff
////////////////////////////////////////////////////////////////////////////////

// Creates a new backoff with constant delay (regardless of the attempt).
// Creates a new backoff with constant delay (for attempt > 0, otherwise the backoff is 0).
func NewConstantBackoff(delay time.Duration) Backoff {
return func(attempt int) time.Duration {
if attempt <= 0 {
return 0
}
return delay
}
}
Expand Down Expand Up @@ -82,7 +86,8 @@ func NewExponentialBackoff(
// will be multiplied by "factor" up to the max value for each attempt
movingMaxMillis := initialMaxDelayMillis

for i := 0; i < attempt; i++ {
// computaion is based on 1 as 0 is the backoff for the first attempt
for i := 1; i < attempt; i++ {
movingMaxMillis = int64(float32(movingMaxMillis) * factor)
// ensure we stay in range
// check for range overflow / numerical overflow
Expand All @@ -97,6 +102,10 @@ func NewExponentialBackoff(
}

return func(attempt int) time.Duration {
if attempt <= 0 {
return 0
}

maxDelayForAttemptMillis := computeMaxDelayForAttempt(attempt)
randomMillisInRange := randRange(minDelayMillis, maxDelayForAttemptMillis)

Expand Down
21 changes: 21 additions & 0 deletions autopaho/backoff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ func TestConstantBackoffNoDelay(t *testing.T) {

for i := 0; i < 100; i++ {
actual := noDelay(i)
if i == 0 {
if actual != 0 {
t.Fatalf("First attempt should not have any delay")
} else {
continue
}
}
if actual != expected {
t.Fatalf("expected value: `%s`, actual `%s`", expected, actual)
}
Expand All @@ -45,6 +52,13 @@ func TestConstantBackoffRandomValue(t *testing.T) {

for i := 0; i < 100; i++ {
actual := nonZeroDelay(i)
if i == 0 {
if actual != 0 {
t.Fatalf("First attempt should not have any delay")
} else {
continue
}
}
if actual != expected {
t.Fatalf("expected value: `%s`, actual `%s`", expected, actual)
}
Expand Down Expand Up @@ -103,6 +117,13 @@ func doSetupAndTestRandomExponentialBackoff(t *testing.T) {
// create many backoffs and test they are within constraints
for i := 0; i < 50; i++ {
actual := exponentialBackoff(i)
if i == 0 {
if actual != 0 {
t.Fatalf("First attempt should not have any delay")
} else {
continue
}
}
if i == 0 && initialMaxDelay < actual {
t.Fatalf("Actual backoff value: `%s` was higher than configured initial maximum: `%s`", actual, initialMaxDelay)
}
Expand Down
6 changes: 5 additions & 1 deletion autopaho/examples/backoff/backoff.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,17 +31,21 @@ func main() {
minBackoff := int64(math.MaxInt64)
maxBackoff := int64(0)
iterationsTotal := 0

zeroAttmeptBackoffTime := backoff(0).Milliseconds()
fmt.Printf("Backoff for attempt '0' : %d\n", zeroAttmeptBackoffTime)

for i := 0; i < 22; i++ {
iterations := interationBase << i
for j := 0; j < iterations; j++ {
iterationsTotal++
backoffTime := backoff(iterationsTotal).Milliseconds()
if backoffTime < minBackoff {
minBackoff = backoffTime
}
if backoffTime > maxBackoff {
maxBackoff = backoffTime
}
iterationsTotal++
}

fmt.Printf("After % 8d iterations, min: %d, max: % 7d\n", iterationsTotal, minBackoff, maxBackoff)
Expand Down
12 changes: 6 additions & 6 deletions autopaho/net.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ func establishServerConnection(ctx context.Context, cfg ClientConfig, firstConne

var attempt int = 0
for {
// Delay before attempting connection
select {
case <-time.After(cfg.ReconnectBackoff(attempt)):
case <-ctx.Done():
return nil, nil
}
for _, u := range cfg.ServerUrls {
connectionCtx, cancelConnCtx := context.WithTimeout(ctx, cfg.ConnectTimeout)

Expand Down Expand Up @@ -105,12 +111,6 @@ func establishServerConnection(ctx context.Context, cfg ClientConfig, firstConne
}
}

// Delay before attempting another connection
select {
case <-time.After(cfg.ReconnectBackoff(attempt)):
case <-ctx.Done():
return nil, nil
}
attempt++
}
}
Expand Down

0 comments on commit 29212b8

Please sign in to comment.