简体   繁体   中英

Redis doesn't return WRONGTYPE as an error in a transaction

Appologies if this was already asked. First, let me show how to reproduce my problem:

  1. Run Redis in a docker container
  2. Connect to Redis and execute the following command:
> SET test 10
  1. In Go, run this code:
func main() {
    redisClient := getConnection() // Abstracting get connection for simplicity

    r, err := redisClient.Do("HSET", "test", "f1", "v1", "f2", "v2")
    fmt.Printf("%+v e: %+v\n")
}

Fair enough, in this step the following error is shown (this means err != nil ):

WRONGTYPE Operation against a key holding the wrong kind of value e: WRONGTYPE Operation against a key holding the wrong kind of value
  1. In comparison, execute the following code:
func main() {
    redisClient := getConnection()

    redisClient.Send("MULTI")

    redisClient.Send("HSET", "test", "f1", "v1", "f2", "v2")

    r, err := redisClient.Do("EXEC")
    fmt.Printf("%+v e: %+v\n")
}

The line being printed is:

WRONGTYPE Operation against a key holding the wrong kind of value e: <nil>

This seems inconsistent to me as I would expect MULTI to return the WRONGTYPE in the error variable as well.

Is this an intended behavior or am I missing something?

There are two results for each command in a Redis transaction. One is the result for adding the command to the transaction and the other is the result for executing the command in the transaction.

The Do method returns the result for adding the command to the transaction.

The Redis EXEC command returns an array where each element is the result of executing the command in the transaction. Examine each element to check individual command errors:

values, err := redis.Values(redisClient.Do("EXEC"))
if err != nil {
    // Handle error
}
if err, ok := values[0].(redis.Error); ok {
    // Handle error for command 0.
    // Adjust the index to match the actual index of 
    // of the HMSET command in the transaction.
}

A helper function for testing transaction command errors may be useful:

func execValues(reply interface{}, err error) ([]interface{}, error) {
    if err != nil {
        return nil, err
    }
    values, ok := reply.([]interface{})
    if !ok {
        return nil, fmt.Errorf("unexpected type for EXEC reply, got type %T", reply)
    }
    for _, v := range values {
        if err, ok := v.(redis.Error); ok {
            return values, err
        }
    }
    return values, nil
}

Use it like this:

values, err := execValues(redisClient.Do("EXEC"))
if err != nil {
    // Handle error.
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM