Skip to content

Commit c34640d

Browse files
Rikkurujoao-r-reis
authored andcommitted
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
1 parent 109a892 commit c34640d

File tree

3 files changed

+88
-8
lines changed

3 files changed

+88
-8
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717
### Fixed
1818

1919
- Retry policy now takes into account query idempotency (CASSGO-27)
20+
- Don't return error to caller with RetryType Ignore (CASSGO-28)
2021

2122
## [1.7.0] - 2024-09-23
2223

query_executor.go

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -165,27 +165,39 @@ func (q *queryExecutor) do(ctx context.Context, qry ExecutableQuery, hostIter Ne
165165
}
166166

167167
// Exit if the query was successful
168-
// or no retry policy defined or retry attempts were reached
169-
if iter.err == nil || !qry.IsIdempotent() || rt == nil || !rt.Attempt(qry) {
168+
// or query is not idempotent or no retry policy defined
169+
if iter.err == nil || !qry.IsIdempotent() || rt == nil {
170170
return iter
171171
}
172-
lastErr = iter.err
172+
173+
attemptsReached := !rt.Attempt(qry)
174+
retryType := rt.GetRetryType(iter.err)
175+
176+
var stopRetries bool
173177

174178
// If query is unsuccessful, check the error with RetryPolicy to retry
175-
switch rt.GetRetryType(iter.err) {
179+
switch retryType {
176180
case Retry:
177181
// retry on the same host
178-
continue
179-
case Rethrow, Ignore:
180-
return iter
181182
case RetryNextHost:
182183
// retry on the next host
183184
selectedHost = hostIter()
184-
continue
185+
case Ignore:
186+
iter.err = nil
187+
stopRetries = true
188+
case Rethrow:
189+
stopRetries = true
185190
default:
186191
// Undefined? Return nil and error, this will panic in the requester
187192
return &Iter{err: ErrUnknownRetryType}
188193
}
194+
195+
if stopRetries || attemptsReached {
196+
return iter
197+
}
198+
199+
lastErr = iter.err
200+
continue
189201
}
190202

191203
if lastErr != nil {

session_test.go

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,3 +347,70 @@ func TestIsUseStatement(t *testing.T) {
347347
}
348348
}
349349
}
350+
351+
type simpleTestRetryPolycy struct {
352+
RetryType RetryType
353+
NumRetries int
354+
}
355+
356+
func (p *simpleTestRetryPolycy) Attempt(q RetryableQuery) bool {
357+
return q.Attempts() <= p.NumRetries
358+
}
359+
360+
func (p *simpleTestRetryPolycy) GetRetryType(error) RetryType {
361+
return p.RetryType
362+
}
363+
364+
// TestRetryType_IgnoreRethrow verify that with Ignore/Rethrow retry types:
365+
// - retries stopped
366+
// - return error is nil on Ignore
367+
// - return error is not nil on Rethrow
368+
// - observed error is not nil
369+
func TestRetryType_IgnoreRethrow(t *testing.T) {
370+
session := createSession(t)
371+
defer session.Close()
372+
373+
var observedErr error
374+
var observedAttempts int
375+
376+
resetObserved := func() {
377+
observedErr = nil
378+
observedAttempts = 0
379+
}
380+
381+
observer := funcQueryObserver(func(ctx context.Context, o ObservedQuery) {
382+
observedErr = o.Err
383+
observedAttempts++
384+
})
385+
386+
for _, caseParams := range []struct {
387+
retries int
388+
retryType RetryType
389+
}{
390+
{0, Ignore}, // check that error ignored even on last attempt
391+
{1, Ignore}, // check thet ignore stops retries
392+
{1, Rethrow}, // check thet rethrow stops retries
393+
} {
394+
retryPolicy := &simpleTestRetryPolycy{RetryType: caseParams.retryType, NumRetries: caseParams.retries}
395+
396+
err := session.Query("INSERT INTO gocql_test.invalid_table(value) VALUES(1)").Idempotent(true).RetryPolicy(retryPolicy).Observer(observer).Exec()
397+
398+
if err != nil && caseParams.retryType == Ignore {
399+
t.Fatalf("[%v] Expected no error, got: %s", caseParams.retryType, err)
400+
}
401+
402+
if err == nil && caseParams.retryType == Rethrow {
403+
t.Fatalf("[%v] Expected unconfigured table error, got: nil", caseParams.retryType)
404+
}
405+
406+
if observedErr == nil {
407+
t.Fatal("Expected unconfigured table error in Obserer, got: nil")
408+
}
409+
410+
if observedAttempts > 1 {
411+
t.Fatalf("Expected one attempt, got: %d", observedAttempts)
412+
}
413+
414+
resetObserved()
415+
}
416+
}

0 commit comments

Comments
 (0)