소스 검색

Add exponential backoff retry policy

Ron Kuris 8 년 전
부모
커밋
31287b6955
3개의 변경된 파일61개의 추가작업 그리고 0개의 파일을 삭제
  1. 1 0
      AUTHORS
  2. 31 0
      policies.go
  3. 29 0
      policies_test.go

+ 1 - 0
AUTHORS

@@ -87,3 +87,4 @@ Vincent Rischmann <me@vrischmann.me>
 Jesse Claven <jesse.claven@gmail.com>
 Derrick Wippler <thrawn01@gmail.com>
 Leigh McCulloch <leigh@leighmcculloch.com>
+Ron Kuris <swcafe@gmail.com>

+ 31 - 0
policies.go

@@ -6,9 +6,12 @@ package gocql
 
 import (
 	"fmt"
+	"math"
+	"math/rand"
 	"net"
 	"sync"
 	"sync/atomic"
+	"time"
 
 	"github.com/hailocab/go-hostpool"
 )
@@ -159,6 +162,34 @@ func (s *SimpleRetryPolicy) Attempt(q RetryableQuery) bool {
 	return q.Attempts() <= s.NumRetries
 }
 
+// ExponentialBackoffRetryPolicy sleeps between attempts
+type ExponentialBackoffRetryPolicy struct {
+	NumRetries int
+	Min, Max   time.Duration
+}
+
+func (e *ExponentialBackoffRetryPolicy) Attempt(q RetryableQuery) bool {
+	if q.Attempts() > e.NumRetries {
+		return false
+	}
+	time.Sleep(e.napTime(q.Attempts()))
+	return true
+}
+
+func (e *ExponentialBackoffRetryPolicy) napTime(attempts int) time.Duration {
+	if e.Min <= 0 {
+		e.Min = 100 * time.Millisecond
+	}
+	if e.Max <= 0 {
+		e.Max = 10 * time.Second
+	}
+	minFloat := float64(e.Min)
+	napDuration := minFloat * math.Pow(2, float64(attempts-1))
+	// add some jitter
+	napDuration += rand.Float64()*minFloat - (minFloat / 2)
+	return time.Duration(napDuration)
+}
+
 type HostStateNotifier interface {
 	AddHost(host *HostInfo)
 	RemoveHost(host *HostInfo)

+ 29 - 0
policies_test.go

@@ -8,6 +8,7 @@ import (
 	"fmt"
 	"net"
 	"testing"
+	"time"
 
 	"github.com/hailocab/go-hostpool"
 )
@@ -272,3 +273,31 @@ func TestSimpleRetryPolicy(t *testing.T) {
 		}
 	}
 }
+
+func TestExponentialBackoffPolicy(t *testing.T) {
+	// test with defaults
+	sut := &ExponentialBackoffRetryPolicy{NumRetries: 2}
+
+	cases := []struct {
+		attempts int
+		delay    time.Duration
+	}{
+
+		{1, 100 * time.Millisecond},
+		{2, (2) * 100 * time.Millisecond},
+		{3, (2 * 2) * 100 * time.Millisecond},
+		{4, (2 * 2 * 2) * 100 * time.Millisecond},
+	}
+	for _, c := range cases {
+		// test 100 times for each case
+		for i := 0; i < 100; i++ {
+			d := sut.napTime(c.attempts)
+			if d < c.delay-(100*time.Millisecond)/2 {
+				t.Fatalf("Delay %d less than jitter min of %d", d, c.delay-100*time.Millisecond/2)
+			}
+			if d > c.delay+(100*time.Millisecond)/2 {
+				t.Fatalf("Delay %d greater than jitter max of %d", d, c.delay+100*time.Millisecond/2)
+			}
+		}
+	}
+}