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?
CodePudding user response:
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
}