SETEX错误 - “使用已关闭的网络连接”

5
我正在使用以下代码在我的Go应用程序中执行SET和EXPIRE操作。
_, err = C.Cache.Do("SETEX", key, 3600, data)

但是我开始遇到一个错误:使用已关闭的网络连接。我使用Gary Burd的Redigo包和RedisLabs。

我的连接Redis的代码如下:

//Connect to cache (Redis)
cache, err := connectToCache()
if err != nil {
    log.Printf("Cache connection settings are invalid")
    os.Exit(1)
}
defer cache.Close()

func connectToCache() (redis.Conn, error) {
    cache, err := redis.Dial("tcp", CACHE_URI)
    if err != nil {
        return nil, err
    }
    _, err = cache.Do("AUTH", CACHE_AUTH)
    if err != nil {
        cache.Close()
        return nil, err
    }
    return cache, nil
}

如果您收到有关已关闭连接的错误消息,则需要重新连接到数据库。这与SETEX命令无关(顺便说一下,在较新版本中,使用带有选项的SET命令取代了SETEX命令)。 - JimB
我已经添加了我的代码以展示我如何管理Redis连接 - 是否存在任何明显的问题?感谢您提供有关SET(带选项)命令的信息。 - tommyd456
我无法从上下文之外的代码中确定延迟将发生在哪里,但是您应该保留连接并尽可能重复使用它们。通常,您需要一个redis.Pool。此外,请参见我的答案:http://stackoverflow.com/questions/30244080/sharing-redis-settings-across-routes/30244721#30244721 - JimB
太好了 - 我不确定什么时候需要一个池,但我想现在是时候了。 - tommyd456
如果@JimB的答案不起作用,那么请使用竞态检测器运行应用程序,并阅读Redigo文档关于并发性 - Charlie Tumahai
1个回答

9
您可以使用redis.Pool来管理多个连接,检查闲置连接是否存活,并自动获取新连接。当拨号建立新连接时,您还可以自动执行AUTH步骤:
func newPool(server, password string) *redis.Pool {
    return &redis.Pool{
        MaxIdle: 3,
        IdleTimeout: 240 * time.Second,
        Dial: func () (redis.Conn, error) {
            c, err := redis.Dial("tcp", server)
            if err != nil {
                return nil, err
            }
            if _, err := c.Do("AUTH", password); err != nil {
                c.Close()
                return nil, err
            }
            return c, err
        },
        TestOnBorrow: func(c redis.Conn, t time.Time) error {
            _, err := c.Do("PING")
            return err
        },
    }
}

var (
    pool *redis.Pool
    redisServer = flag.String("redisServer", ":6379", "")
    redisPassword = flag.String("redisPassword", "", "")
)

func main() {
    flag.Parse()
    pool = newPool(*redisServer, *redisPassword)
    ...
}

所以正如你在另一个答案中指出的那样,我只需要每次需要新连接时使用类似conn = pool.Get()的东西? - tommyd456
@tommyd456:是的,每次需要连接时都要调用pool.Get(),然后调用conn.Close将连接返回到池中。 - JimB
我认为推迟关闭操作是更可取的。 - tommyd456
而且,由于这是我正在制作的API - 我是否会在每次访问路由之前创建连接,就在Redis操作本身之前? - tommyd456
@tommyd456:是的,你需要确保调用Close方法,否则连接将无法返回到池中。当你需要连接时,从池中获取连接,完成后将其归还。 - JimB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接