|
@@ -15,7 +15,6 @@ import (
|
|
|
"io"
|
|
"io"
|
|
|
"io/ioutil"
|
|
"io/ioutil"
|
|
|
"net"
|
|
"net"
|
|
|
- "os"
|
|
|
|
|
"strings"
|
|
"strings"
|
|
|
"sync"
|
|
"sync"
|
|
|
"sync/atomic"
|
|
"sync/atomic"
|
|
@@ -283,46 +282,12 @@ func TestTimeout(t *testing.T) {
|
|
|
wg.Wait()
|
|
wg.Wait()
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-type testRetryPolicy struct {
|
|
|
|
|
- numRetries int // maximum number of times to retry a query
|
|
|
|
|
- attemptTimeout time.Duration
|
|
|
|
|
- t *testing.T
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// Attempt tells gocql to attempt the query again based on query.Attempts being less
|
|
|
|
|
-// than the NumRetries defined in the policy.
|
|
|
|
|
-func (s *testRetryPolicy) Attempt(q RetryableQuery) bool {
|
|
|
|
|
- return q.Attempts() <= s.numRetries
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-func (s *testRetryPolicy) GetRetryType(err error) RetryType {
|
|
|
|
|
- return Retry
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-// AttemptTimeout satisfies the optional RetryPolicyWithAttemptTimeout interface.
|
|
|
|
|
-func (s *testRetryPolicy) AttemptTimeout() time.Duration {
|
|
|
|
|
- return s.attemptTimeout
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-type testQueryObserver struct{}
|
|
|
|
|
-
|
|
|
|
|
-func (o *testQueryObserver) ObserveQuery(ctx context.Context, q ObservedQuery) {
|
|
|
|
|
- Logger.Printf("Observed query %q. Returned %v rows, took %v on host %q. Error: %q\n", q.Statement, q.Rows, q.End.Sub(q.Start), q.Host.ConnectAddress().String(), q.Err)
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
// TestQueryRetry will test to make sure that gocql will execute
|
|
// TestQueryRetry will test to make sure that gocql will execute
|
|
|
// the exact amount of retry queries designated by the user.
|
|
// the exact amount of retry queries designated by the user.
|
|
|
func TestQueryRetry(t *testing.T) {
|
|
func TestQueryRetry(t *testing.T) {
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
|
defer cancel()
|
|
defer cancel()
|
|
|
|
|
|
|
|
- log := &testLogger{}
|
|
|
|
|
- Logger = log
|
|
|
|
|
- defer func() {
|
|
|
|
|
- Logger = &defaultLogger{}
|
|
|
|
|
- os.Stdout.WriteString(log.String())
|
|
|
|
|
- }()
|
|
|
|
|
-
|
|
|
|
|
srv := NewTestServer(t, defaultProto, ctx)
|
|
srv := NewTestServer(t, defaultProto, ctx)
|
|
|
defer srv.Stop()
|
|
defer srv.Stop()
|
|
|
|
|
|
|
@@ -341,24 +306,22 @@ func TestQueryRetry(t *testing.T) {
|
|
|
}
|
|
}
|
|
|
}()
|
|
}()
|
|
|
|
|
|
|
|
- rt := &testRetryPolicy{numRetries: 2, t: t, attemptTimeout: time.Millisecond * 25}
|
|
|
|
|
- queryCtx, cancel := context.WithTimeout(context.Background(), time.Millisecond*90)
|
|
|
|
|
- defer cancel()
|
|
|
|
|
- qry := db.Query("slow").RetryPolicy(rt).Observer(&testQueryObserver{}).WithContext(queryCtx)
|
|
|
|
|
|
|
+ rt := &SimpleRetryPolicy{NumRetries: 1}
|
|
|
|
|
+
|
|
|
|
|
+ qry := db.Query("kill").RetryPolicy(rt)
|
|
|
if err := qry.Exec(); err == nil {
|
|
if err := qry.Exec(); err == nil {
|
|
|
t.Fatalf("expected error")
|
|
t.Fatalf("expected error")
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // wait for the last slow query to finish
|
|
|
|
|
- // this prevents the test from flaking because of writing to a connection that's been closed
|
|
|
|
|
- time.Sleep(100 * time.Millisecond)
|
|
|
|
|
-
|
|
|
|
|
- numQueries := atomic.LoadUint64(&srv.nQueries)
|
|
|
|
|
|
|
+ requests := atomic.LoadInt64(&srv.nKillReq)
|
|
|
|
|
+ attempts := qry.Attempts()
|
|
|
|
|
+ if requests != int64(attempts) {
|
|
|
|
|
+ t.Fatalf("expected requests %v to match query attempts %v", requests, attempts)
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // the 90ms timeout allows at most 4 retries but the maximum is 2 as per the retry policy
|
|
|
|
|
- // the number of queries therefore needs to be 3 (initial query + 2 retries)
|
|
|
|
|
- if numQueries != 3 {
|
|
|
|
|
- t.Fatalf("Number of queries should be 3 but query executed %v times", numQueries)
|
|
|
|
|
|
|
+ // the query will only be attempted once, but is being retried
|
|
|
|
|
+ if requests != int64(rt.NumRetries) {
|
|
|
|
|
+ t.Fatalf("failed to retry the query %v time(s). Query executed %v times", rt.NumRetries, requests-1)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -812,7 +775,6 @@ type TestServer struct {
|
|
|
nreq uint64
|
|
nreq uint64
|
|
|
listen net.Listener
|
|
listen net.Listener
|
|
|
nKillReq int64
|
|
nKillReq int64
|
|
|
- nQueries uint64
|
|
|
|
|
compressor Compressor
|
|
compressor Compressor
|
|
|
|
|
|
|
|
protocol byte
|
|
protocol byte
|
|
@@ -928,7 +890,6 @@ func (srv *TestServer) process(f *framer) {
|
|
|
f.writeHeader(0, opSupported, head.stream)
|
|
f.writeHeader(0, opSupported, head.stream)
|
|
|
f.writeShort(0)
|
|
f.writeShort(0)
|
|
|
case opQuery:
|
|
case opQuery:
|
|
|
- atomic.AddUint64(&srv.nQueries, 1)
|
|
|
|
|
query := f.readLongString()
|
|
query := f.readLongString()
|
|
|
first := query
|
|
first := query
|
|
|
if n := strings.Index(query, " "); n > 0 {
|
|
if n := strings.Index(query, " "); n > 0 {
|