英文:
Redis GET returns short write error in Go
问题
我有一些代码,用于在给定的频率上跨进程调度作业:
func doMasterInner(ctx context.Context, conn redis.Conn, suffix string,
freq time.Duration, op func(context.Context) error) error {
key := fmt.Sprintf("myserviced_%s", suffix)
_, err := redis.Int(conn.Do("GET", key))
var shouldRun bool
if err != nil {
if err != redis.ErrNil {
return fmt.Errorf("从Redis获取%s失败,错误:%v", key, err)
}
shouldRun = true
if _, err := conn.Do("SETEX", key, int(freq.Seconds()), 0); err != nil {
return fmt.Errorf("在Redis中设置%s的定时器失败,错误:%v", key, err)
}
}
if shouldRun {
return op(ctx)
}
return nil
}
然而,当我调用这段代码时:
pool := &redis.Pool{
MaxIdle: 3,
MaxActive: 4,
Wait: true,
IdleTimeout: 240 * time.Second,
Dial: func() (redis.Conn, error) {
return redis.Dial("tcp", addr,
redis.DialPassword(password),
redis.DialConnectTimeout(5 * time.Second))
},
}
conn := pool.Get()
defer conn.Close()
err := doMasterInner(context.Background(), conn, "assets", time.Hour,
func(ctx context.Context) error {
// 在这里做一些操作
return nil
})
fmt.Printf("错误:%v", err)
打印函数输出 从Redis获取myserviced_assets失败,错误:short write
。我不确定为什么会发生这种情况,因为这个错误消息表明是 GET
操作失败了。是什么导致Redis返回 short write
的消息?
英文:
I have some code to schedule jobs across processes on a given frequency:
func doMasterInner(ctx context.Context, conn redis.Conn, suffix string,
freq time.Duration, op func(context.Contex) error) error {
key := fmt.Sprintf("myserviced_%s", suffix)
_, err := redis.Int(conn.Do("GET", key))
var shouldRun bool
if err != nil {
if err != redis.ErrNil {
return fmt.Errorf("Failed to get %s from Redis, error: %v", key, err)
}
shouldRun = true
if _, err := conn.Do("SETEX", key, int(freq.Seconds()), 0); err != nil {
return fmt.Errorf("Failed to set timer for %s in Redis, error: %v", key, err)
}
}
if shouldRun {
return op(ctx)
}
return nil
}
However, when I call this code:
pool := &redis.Pool{
MaxIdle: 3,
MaxActive: 4,
Wait: true,
IdleTimeout: 240 * time.Second,
Dial: func() (redis.Conn, error) {
return redis.Dial("tcp", addr,
redis.DialPassword(password),
redis.DialConnectTimeout(5 * time.Second))
},
}
conn := pool.Get()
defer conn.Close()
err := doMasterInner(context.Background(), conn, "assets", time.Hour,
func(ctx context.Context) error {
// do something here
return nil
})
fmt.Printf("Error: %v", err)
The print function prints Failed to get myserviced_assets from Redis, error: short write
. I'm not sure why this is happening as this error message indicates that it is the GET
that is failing. What causes Redis to return a short write
message on a GET?
答案1
得分: 1
所以,这段代码本身并不是问题所在。真正的问题是我在使用这段代码时,同时使用相同的redis.Conn
对象并发调用多个doMasterInner
实例。虽然我不确定是什么原因导致了这个问题,但我猜测多个线程尝试向同一个redis.Conn
缓冲区写入可能导致了错误。像这样修改doMasterInner
可以解决这个问题:
func doMasterInner(ctx context.Context, pool *redis.Pool, suffix string,
freq time.Duration, op func(context.Context) error) error {
conn := pool.Get()
defer conn.Close()
key := fmt.Sprintf("myserviced_%s", suffix)
_, err := redis.Int(conn.Do("GET", key))
var shouldRun bool
if err != nil {
if err != redis.ErrNil {
return fmt.Errorf("Failed to get %s from Redis, error: %v", key, err)
}
shouldRun = true
if _, err := conn.Do("SETEX", key, int(freq.Seconds()), 0); err != nil {
return fmt.Errorf("Failed to set timer for %s in Redis, error: %v", key, err)
}
}
if shouldRun {
return op(ctx)
}
return nil
}
请注意,我已经将参数conn
改为pool
,以避免与内部变量冲突。
英文:
So, this code in and of itself wasn't the issue. The real issue was that I was using this code and calling many instances of doMasterInner
concurrently with the same redis.Conn
object. Although I'm not exactly sure what caused this issue, my guess is that having multiple threads attempting to write to the same redis.Conn
buffer caused the error. Modifying doMasterInner
like this fixed the issue:
func doMasterInner(ctx context.Context, conn *redis.Pool, suffix string,
freq time.Duration, op func(context.Contex) error) error {
conn := pool.Get()
defer conn.Close()
key := fmt.Sprintf("myserviced_%s", suffix)
_, err := redis.Int(conn.Do("GET", key))
var shouldRun bool
if err != nil {
if err != redis.ErrNil {
return fmt.Errorf("Failed to get %s from Redis, error: %v", key, err)
}
shouldRun = true
if _, err := conn.Do("SETEX", key, int(freq.Seconds()), 0); err != nil {
return fmt.Errorf("Failed to set timer for %s in Redis, error: %v", key, err)
}
}
if shouldRun {
return op(ctx)
}
return nil
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论