Redis GET在Go中返回短写错误。

huangapple go评论82阅读模式
英文:

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
}

huangapple
  • 本文由 发表于 2022年9月8日 15:37:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/73645313.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定