Aerospike randomly returning nil errors when using Query() with Go client


#1

I’m experiencing some strange behavior. I’m trying to set up a small webapp that fetches some data using Aerospike 3.5 Community running on an Ubuntu 12.04 server. I’m using the default aerospike.conf file (using the ‘test’ namespace) and am following the example of how to query here.

When I attempt to query some records with a filter, the Errors channel randomly is returning a nil error. (This example points to my dev database instance).

To replicate, compile and run the following multiple times, you’ll see either data returned or a panic:

package main

import (
    "fmt"

    "github.com/aerospike/aerospike-client-go"
)

func main() {

    c, err := aerospike.NewClient("52.7.157.46", 3000)
    if err != nil {
        panic(err)
    }

    recs := liststuff(c)

    fmt.Printf("got results: %v", recs)
}

func liststuff(client *aerospike.Client) []*aerospike.Record {

    // fetch some records with a filter
    stm := aerospike.NewStatement("test", "products")
    stm.Addfilter(aerospike.NewEqualFilter("visible", 1))
    fmt.Println("querying...")
    recordset, err := client.Query(nil, stm)
    if err != nil {
        panic(err)
    }

    // collect results into a slice
    recs := []*aerospike.Record{}
L:
    for {
        select {
        case rec, chanOpen := <-recordset.Records:
            if !chanOpen {
                break L
            }
            fmt.Println("found record %v", rec)
            recs = append(recs, rec)
        case err := <-recordset.Errors:
            if err != nil {
                panic(err)
            } else {
                panic(fmt.Errorf("error nil when it should exist"))
            }
            return nil
        }
    }

    return recs
}

#2

Hi, bug is confirmed and will be fixed in the next version.

Thank you for your report.


#3

Nicholas,

Seems I mistook this issue with another one. Both Errors and Records channels are closed automatically when the record stream is over from the server-side, hence the nil value from the Errors channel.

Here is a simple code snippet that shows the mechanism: https://play.golang.org/p/xp30vztKZb

I stream-lined the Recordset API a while back to work around the ugly select pattern, so you’ll have a much more fun doing the following (it is goroutine friendly and is multiplexing the channels behind the scene):


package main

import (
    "fmt"

    "github.com/aerospike/aerospike-client-go"
)

func main() {

    c, err := aerospike.NewClient("52.7.157.46", 3000)
    if err != nil {
        panic(err)
    }

    recs := liststuff(c)

    fmt.Printf("got results: %v", recs)
}

func liststuff(client *aerospike.Client) []*aerospike.Record {

    // fetch some records with a filter
    stm := aerospike.NewStatement("test", "products")
    stm.Addfilter(aerospike.NewEqualFilter("visible", 1))
    fmt.Println("querying...")
    recordset, err := client.Query(nil, stm)
    if err != nil {
        panic(err)
    }

    // collect results into a slice
    recs := []*aerospike.Record{}

    // You can call 'Results()' method in multiple goroutines. It is simply multiplexing
    // The Errors and Records channels, and managing the select complexity behind the scenes.
    for result := range recordset.Results() {
        if result.Err != nil {
            panic(err)
        }
        fmt.Println("found record %v", result.Record)
        recs = append(recs, result.Record)
    }

    return recs
}

In case you came across the old select pattern somewhere in our documentation, kindly point me to it so that I can update the example to the newer Results() API.


#4

Ok thanks. The example was:

  1. here: https://github.com/aerospike/aerospike-client-go/blob/master/docs/client.md#query
  2. and here for scan all: https://github.com/aerospike/aerospike-client-go/blob/master/docs/client.md#scanallpolicy-scanpolicy-namespace-string-setname-string-binnames-string-recordset-error
  3. for scan test: https://github.com/aerospike/aerospike-client-go/blob/master/scan_test.go
  4. probably for other tests (a lot of people look at the tests to see how to use the API). I recommend just doing a search all for it

Thanks for clarifying!