chengdol
chengdol

Reputation: 229

How do I make the Cassandra gocql retry policy work?

Context: I need to retry a query to read a column until it does not failed by "not found" error.

From the documentation: https://pkg.go.dev/github.com/gocql/gocql#Query.RetryPolicy

I have code like below, but the retry never works =) :

package main

import (
  "context"
  "fmt"
  "log"
  "time"

  "github.com/gocql/gocql"
)

// custom retry policy
type RP struct {
  NumRetries int //Number of times to retry a query
}

func (s *RP) Attempt(q gocql.RetryableQuery) bool {
  fmt.Printf("I am in retry attempt!")
  if q.Attempts() > s.NumRetries {
    return false
  }
  time.Sleep(3 * time.Second)
  return true
}

func (s *RP) GetRetryType(err error) gocql.RetryType {
  fmt.Printf("I am in retry GetRetryType!")
  return gocql.Retry
}

func main() {
  // I have already populated the data in the cassandra table
  // it is a local cassandra single docker node
  cluster := gocql.NewCluster("192.168.8.4")
  cluster.Keyspace = "store"
  cluster.ProtoVersion = 4
  session, err := cluster.CreateSession()
  if err != nil {
    log.Fatalln(err)
  }
  defer session.Close()

  ctx := context.Background()
  var count int

  // There is no "123" userid, so it is expected to fail and trigger retry
  q := session.Query(`SELECT item_count FROM shopping_cart WHERE userid=?;`, "123").Idempotent(true).RetryPolicy(&RP{
    NumRetries: 10,
  }).WithContext(ctx)
  err = q.Scan(&count)

  // below print values are good
  fmt.Printf("idempotent: %v\n", q.IsIdempotent())
  fmt.Printf("attempt: %v\n", q.Attempts())           
  fmt.Printf("consistency: %v\n", q.GetConsistency())
  fmt.Printf("context: %v\n", q.Context())

  if err != nil {
    log.Fatalln(err)
  }
  fmt.Printf("the count is %d\n\n", count)

However, the query only runs once and the err terminates the program. I did not see message: I am in retry attempt! or I am in retry GetRetryType!.

I wonder whether or not my understanding of the retry is wrong, from the doc:

RetryPolicy interface is used by gocql to determine if a query can be attempted again 
after a retryable error has been received. The interface allows gocql users to implement 
their own logic to determine if a query can be attempted again.

Any help will be appreciated!

Upvotes: 0

Views: 377

Answers (1)

Erick Ramirez
Erick Ramirez

Reputation: 16353

The GoCQL driver is working as expected and your assumption here is incorrect:

  // There is no "123" userid, so it is expected to fail and trigger retry

A read request which does not return a non-existent partition in the result is not a failure.

The types of read request failures include:

  • read timeouts - the replicas did not respond within read_request_timeout_in_ms
  • unavailable errors - not enough replicas responded to the coordinator to satisfy the required consistency level
  • server errors - some machine-related error (not Cassandra) took place on the server-side
  • overloaded exception - the request did not get processed because the coordinator was overloaded
  • read failure exception - specifically related to too many tombstones were scanned, breaching the tombstone_failure_threshold

The example you posted is a successful query and not a failure. Only when a request fails does the configured retry policy get triggered to determine whether to retry the query. Cheers!

Upvotes: 1

Related Questions