0

我尝试通过代码进行调试,它似乎主要是在多个客户端试图修改事务中的相同键时重现。重试事务通常会消除错误,但是首先抛出异常有什么原因吗?

我试图执行的代码非常简单:

var existingValue = db.HashGetAsync(hashKey, field);
var t = db.CreateTransaction();
t.AddCondition(Condition.HashEqual(hashKey, field, existingValue));
t.HashSetAsync(hashKey, field, newValue, flags: CommandFlags.FireAndForget);
bool succeeded = await t.ExecuteAsync(); // StackExchange.Redis.RedisConnectionException thrown intermittently
4

1 回答 1

1

当您尝试同时从 2 个不同的线程更新同一个键时,会发生此异常。如果您为每个应用程序使用一个 ConnectionMultiplexer(如推荐的那样),则仅当从不同的应用程序或主机访问密钥时才会发生。

当您以事务方式更新值时,如果更新失败,您应该重试(transaction.ExecuteAsync() 返回 false 或“对 EXEC 的意外响应:MultiBulk:0 项”异常被抛出)。

这是一种以事务方式更新字符串值的方法:

    public async Task<string> UpdateValueAsync(string key, Func<string, string> updateAction)
    {
        for (int i = 0; i < UpdateRetryCount; i++)
        {
            var oldValue = await database.StringGetAsync(key);

            if (oldValue.IsNull)
                throw new InvalidOperationException(string.Format("Key \"{0}\" not found.", key));

            var newValue = updateAction(oldValue);

            var transaction = database.CreateTransaction();
            transaction.AddCondition(Condition.StringEqual(key, oldValue));
            transaction.StringSetAsync(key, newValue);

            try
            {
                if (await transaction.ExecuteAsync())
                {
                    return newValue;
                }
            }
            catch (RedisConnectionException exception)
            {
                if (exception.Message != "Unexpected response to EXEC: MultiBulk: 0 items")
                {
                    throw;
                }
            }
        }

        throw new InvalidOperationException(string.Format("Failed to update value in key {0}.", key));
    }
于 2015-05-08T14:07:53.130 回答