Description
A sample program:
package main
import (
"fmt"
"net/http"
_ "net/http/pprof"
"time"
"github.com/gomodule/redigo/redis"
rg "github.com/redislabs/redisgraph-go"
"github.com/sirupsen/logrus"
)
func process() {
for {
queryStr := fmt.Sprintf("MATCH (X) RETURN X")
_ = query("mesh7Graph", queryStr)
logrus.Println("blah")
}
}
func query(graphName, query string) error {
conn := pool.Get()
defer conn.Close()
g := rg.GraphNew(graphName, conn)
if false {
_, err := g.Query(query)
if err != nil {
logrus.Errorf("GraphDB query error: %v", err)
return err
}
} else {
res, err := g.Query(query)
if err != nil {
logrus.Errorf("GraphDB query error: %v", err)
return err
}
for res.Next() {
_ = res.Record()
}
}
return nil
}
var pool *redis.Pool
const (
address = "<REDIS_SERVER_URL>:6379"
password = "<REDIS_PASSWORD>"
)
func main() {
pool = &redis.Pool{
MaxIdle: 100,
MaxActive: 100,
IdleTimeout: 240 * time.Second,
// Dial or DialContext must be set.
// When both are set, DialContext takes precedence over Dial.
Dial: func() (redis.Conn, error) {
c, err := redis.Dial("tcp", address)
logrus.Tracef("Dialing redis @ %v", address)
if err != nil {
logrus.Errorf("Dial failed. Error: %v", err)
return nil, err
}
if _, err := c.Do("AUTH", password); err != nil {
logrus.Errorf("Authorization failed. Error: %v", err)
c.Close()
return nil, err
}
return c, nil
},
TestOnBorrow: func(c redis.Conn, t time.Time) error {
if time.Since(t) < time.Minute {
return nil
}
_, err := c.Do("PING")
return err
},
}
go process()
logrus.Fatal(http.ListenAndServe("localhost:8080", nil))
}
Now run the above program toggling the if
block with false
and true
. The program will just continuously do some redisgraph calls and not parse the response in one case, will parse the response in another case.
When the above program is running, do:
curl -sK -v http://localhost:8080/debug/pprof/heap > heap.out
go tool pprof heap.out
(pprof) lines
(pprof) web
In the case when we ignore the output of Query
function, we get a memory leak in the pprof
output. When the response is parsed and the record
are read, there is no leak reported in the pprof
output.
The docs do not mention anything about reading the Query
function output. There is no close
function on the QueryResult
struct either, if I have to call it via defer
. There is no other function except Query
(like an Exec
in the SQL) which I can do to not read results.
I will be happy to provide any other debugging information if you want.