1

My application is using redigo client library to establish TCP connection with redis server. I want to change the password of the redis at run-time and want the redigo library to use the new password in subsequent connections. ( in redis pool )

I have defined my redis-pool object in the following way to achieve that.

 return &redis.Pool{
        MaxIdle:     5,
        MaxActive:   1000,
        IdleTimeout: time.Minute,
        Dial: func() (redis.Conn, error) {
            cErr = getRedisPassword()
            if cErr != nil {
                return nil, cErr
            }

                   if gRedisAuthPassword != "" {
                           opts[1] =  redis.DialPassword(gRedisAuthPassword)
                   }
            return redis.Dial("tcp", addr, opts...)
        },
        TestOnBorrow: func(c redis.Conn, t time.Time) error {
            _, err := c.Do("PING")
            cErr = err
            return err
        },
    }, nil

Options while calling the function were :

  cluster := &redisc.Cluster{
        StartupNodes: nodesInfo,
        DialOptions:  []redis.DialOption{redis.DialConnectTimeout(5 * time.Second), redis.DialPassword(gRedisAuthPassword)},
        CreatePool:   createPool,

getRedisPassword Function looks like this : This function does call a script which fetches the latest password of the redis cluster.

func getRedisPassword() error {
        var cErr error
        cErr = nil

        if ssFlag == "YES" {
             cmd := exec.Command("/bin/bash", "-c", "/opt/lte/etc/utility/fetch_redisPassword.sh")
             pass, err := cmd.CombinedOutput()
             gRedisAuthPassword = string(pass)
             cErr = err

             // Wait for the process to finish or kill it after a timeout (whichever happens first):
             done := make(chan error, 1)
             go func() {
                     done <- cmd.Wait()
             }()
                  select {
                          case <-time.After(3 * time.Second):
                                  if err := cmd.Process.Kill(); err != nil {
                                   fmt.Println("error:", err)
                                  }
                          case err := <-done:
                                    if err != nil {
                                    fmt.Println("error:", err)
                                        }
                  }
        } else {
                return cErr
        }

        if cErr != nil || gRedisAuthPassword == "null" || gRedisAuthPassword == "" {
          //print log
                        cErr = ErrDbConnFailed
        }

        return cErr
}

I am facing two issues while calling the function:

  1. Lots of curl connections being established and left hanging.
  2. Heavy load causes the goroutine/threads to exhaust.
  3. Script process does not get terminated.

Can you help me with a better method to achieve the same? Thanks in advance.

  • 2
    Adjust the pool parameters to reduce connection dialing. Move the whatever /opt/lte/etc/utility/fetch_redisPassword.sh does to Go code. – Charlie Tumahai Nov 06 '20 at 17:14
  • Aside: CombinedOutput returns after the command is done (how else could it returns its output?). There's no point calling Wait afterwards, and the timeout code doesn't do anything. Use CommandContext to enforce a timeout. That being said, I agree that you should probably just implement whatever the shell script does in Go. – Peter Nov 06 '20 at 23:52
  • @Peter Thanks. I was also wndering if the modification code is correct ? The line -- opts[1] = redis.DialPassword(gRedisAuthPassword) . Is this correct way to modify the parameter.? – Mohit Goyal Nov 08 '20 at 07:15

0 Answers0