1

so, i have a necessity to connect to 3 redis server. i create 3 connection pool, and initialize each of them. but redigo seems only connected to single redis server, although i get the connection using different pool.

using redigo, here's my code below

import (
    "fmt"
    "time"
    "github.com/garyburd/redigo/redis"
)

var poolA *redis.Pool
var poolB *redis.Pool
var poolC *redis.Pool

func main() {
    poolA = &redis.Pool{}
    poolB = &redis.Pool{}
    poolC = &redis.Pool{}

    connections := []string{"localhost:6379", "localhost2:6379", "localhost3:6379"}

    for k, v := range connections {
        redisPool := &redis.Pool{
            Dial: func() (redis.Conn, error) {
                return redis.Dial("tcp", v)
            },
            TestOnBorrow: func(c redis.Conn, t time.Time) error {
                if time.Since(t) < time.Minute {
                    return nil
                }
                _, err := c.Do("PING")
                return err
            },
            IdleTimeout: time.Duration(10) * time.Second,
            MaxActive:   100,
            MaxIdle:     100 / 2,
            Wait:        true,
        }

        if k == 0 {
            fmt.Println("poolA:", v)
            poolA = redisPool
        }
        if k == 1 {
            fmt.Println("poolB:", v)
            poolB = redisPool
        }
        if k == 2 {
            fmt.Println("poolC:", v)
            poolC = redisPool
        }
    }

    con := poolA.Get()
    defer con.Close()
    count, err := redis.Int(con.Do("SADD", "any:test", 3246))
    if err != nil {
        fmt.Println("error querying redis:", err.Error())
    }
    fmt.Println("count=", count)

    con2 := poolB.Get()
    defer con2.Close()
    count, err = redis.Int(con2.Do("SADD", "any:test", 3246))
    if err != nil {
        fmt.Println("error querying redis:", err.Error())
    }
    fmt.Println("count=", count)

    con3 := poolC.Get()
    defer con3.Close()
    count, err = redis.Int(con3.Do("SADD", "any:test", 3246))
    if err != nil {
        fmt.Println("error querying redis:", err.Error())
    }
    fmt.Println("count=", count)
}

the problem is, all 3 pools are connecting to the last server/connection, resulting just as below. any idea?

poolA: localhost:6379
poolB: localhost2:6379
poolC: localhost3:6379
error querying redis: dial tcp: lookup localhost3: no such host
count= 0
error querying redis: dial tcp: lookup localhost3: no such host
count= 0
error querying redis: dial tcp: lookup localhost3: no such host
count= 0

Process finished with exit code 0
TheHippo
  • 61,720
  • 15
  • 75
  • 100
boes
  • 13
  • 3
  • it's solved now, a golang common mistake in for loop. https://github.com/golang/go/wiki/CommonMistakes – boes Nov 17 '17 at 04:14

1 Answers1

1

The dial functions use the single variable v. The functions use the last value assigned to v when called.

To fix the problem, declare a variable inside the scope of the for loop and use that variable in the dial function:

for k, v := range connections {
    v := v // Declare variable scoped inside for loop 
    redisPool := &redis.Pool{
        Dial: func() (redis.Conn, error) {
            return redis.Dial("tcp", v)  // uses variable scoped inside for loop
        },
    ...

Separate from this issue, the pool settings don't make sense. Because the pool is configured to discard connections that have been idle for 10 seconds, the test on borrow function never pings the server.

Charlie Tumahai
  • 113,709
  • 12
  • 249
  • 242
  • didn't work, same thing. i even do not use for loop, but initialize 2 redis pool separately, the two of them connect to the same server, not to different server as intentional. btw, i'm just following the sample in redigo documentation, so what do you suggest for TestOnBorrow? – boes Nov 17 '17 at 03:27
  • sorry, i had a typo. it's working like you suggested. thanks a lot – boes Nov 17 '17 at 04:03