This is an automated email from the ASF dual-hosted git repository. joaoreis pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/cassandra-gocql-driver.git
The following commit(s) were added to refs/heads/trunk by this push: new c34640d Don't return error to caller with RetryType Ignore c34640d is described below commit c34640dc8ca1047334da1d7b5689725c2be21061 Author: Rikkuru <5867722+rikk...@users.noreply.github.com> AuthorDate: Thu Nov 21 20:27:24 2024 +0300 Don't return error to caller with RetryType Ignore RetryType Ignore is documented and should work according to the documentation. Error is not returned to caller on ignore but can be seen in ObservedQuery. RetryType should be checked even if RetryPolicy.Attempt returns false, otherwise Ignore will not work on last attempt. Patch by Rikkuru; reviewed by João Reis, Jackson Fleming for CASSGO-28 --- CHANGELOG.md | 1 + query_executor.go | 28 ++++++++++++++++------- session_test.go | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c00549..a83e6f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed - Retry policy now takes into account query idempotency (CASSGO-27) +- Don't return error to caller with RetryType Ignore (CASSGO-28) ## [1.7.0] - 2024-09-23 diff --git a/query_executor.go b/query_executor.go index 0368736..d6be02e 100644 --- a/query_executor.go +++ b/query_executor.go @@ -165,27 +165,39 @@ func (q *queryExecutor) do(ctx context.Context, qry ExecutableQuery, hostIter Ne } // Exit if the query was successful - // or no retry policy defined or retry attempts were reached - if iter.err == nil || !qry.IsIdempotent() || rt == nil || !rt.Attempt(qry) { + // or query is not idempotent or no retry policy defined + if iter.err == nil || !qry.IsIdempotent() || rt == nil { return iter } - lastErr = iter.err + + attemptsReached := !rt.Attempt(qry) + retryType := rt.GetRetryType(iter.err) + + var stopRetries bool // If query is unsuccessful, check the error with RetryPolicy to retry - switch rt.GetRetryType(iter.err) { + switch retryType { case Retry: // retry on the same host - continue - case Rethrow, Ignore: - return iter case RetryNextHost: // retry on the next host selectedHost = hostIter() - continue + case Ignore: + iter.err = nil + stopRetries = true + case Rethrow: + stopRetries = true default: // Undefined? Return nil and error, this will panic in the requester return &Iter{err: ErrUnknownRetryType} } + + if stopRetries || attemptsReached { + return iter + } + + lastErr = iter.err + continue } if lastErr != nil { diff --git a/session_test.go b/session_test.go index 0319a8a..c7bafbb 100644 --- a/session_test.go +++ b/session_test.go @@ -347,3 +347,70 @@ func TestIsUseStatement(t *testing.T) { } } } + +type simpleTestRetryPolycy struct { + RetryType RetryType + NumRetries int +} + +func (p *simpleTestRetryPolycy) Attempt(q RetryableQuery) bool { + return q.Attempts() <= p.NumRetries +} + +func (p *simpleTestRetryPolycy) GetRetryType(error) RetryType { + return p.RetryType +} + +// TestRetryType_IgnoreRethrow verify that with Ignore/Rethrow retry types: +// - retries stopped +// - return error is nil on Ignore +// - return error is not nil on Rethrow +// - observed error is not nil +func TestRetryType_IgnoreRethrow(t *testing.T) { + session := createSession(t) + defer session.Close() + + var observedErr error + var observedAttempts int + + resetObserved := func() { + observedErr = nil + observedAttempts = 0 + } + + observer := funcQueryObserver(func(ctx context.Context, o ObservedQuery) { + observedErr = o.Err + observedAttempts++ + }) + + for _, caseParams := range []struct { + retries int + retryType RetryType + }{ + {0, Ignore}, // check that error ignored even on last attempt + {1, Ignore}, // check thet ignore stops retries + {1, Rethrow}, // check thet rethrow stops retries + } { + retryPolicy := &simpleTestRetryPolycy{RetryType: caseParams.retryType, NumRetries: caseParams.retries} + + err := session.Query("INSERT INTO gocql_test.invalid_table(value) VALUES(1)").Idempotent(true).RetryPolicy(retryPolicy).Observer(observer).Exec() + + if err != nil && caseParams.retryType == Ignore { + t.Fatalf("[%v] Expected no error, got: %s", caseParams.retryType, err) + } + + if err == nil && caseParams.retryType == Rethrow { + t.Fatalf("[%v] Expected unconfigured table error, got: nil", caseParams.retryType) + } + + if observedErr == nil { + t.Fatal("Expected unconfigured table error in Obserer, got: nil") + } + + if observedAttempts > 1 { + t.Fatalf("Expected one attempt, got: %d", observedAttempts) + } + + resetObserved() + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@cassandra.apache.org For additional commands, e-mail: commits-h...@cassandra.apache.org