如果您查看RedisLock.cs类的代码,您可以看到它正在读取锁定值以在Redis外部验证超时,并且如果没有人触摸它,它也会使用Watch和Unwatch来覆盖超时值 .

换句话说,使用Watch和unwatch并提交的确切要点是什么,而我们可以使用更可靠的Redis内部设置超时?

ExecUtils.RetryUntilTrue(() =>{
    //This pattern is taken from the redis command for SETNX http://redis.io/commands/setnx

    //Calculate a unix time for when the lock should expire
    var realSpan = timeOut ?? new TimeSpan(365, 0, 0, 0); //if nothing is passed in the timeout hold for a year
    var expireTime = DateTime.UtcNow.Add(realSpan);
    var lockString = (expireTime.ToUnixTimeMs() + 1).ToString();

    //Try to set the lock, if it does not exist this will succeed and the lock is obtained
    var nx = redisClient.SetValueIfNotExists(key, lockString);
    if (nx)
        return true;

    //If we've gotten here then a key for the lock is present. This could be because the lock is
    //correctly acquired or it could be because a client that had acquired the lock crashed (or didn't release it properly).
    //Therefore we need to get the value of the lock to see when it should expire

    redisClient.Watch(key);
    var lockExpireString = redisClient.Get<string>(key);
    if (!long.TryParse(lockExpireString, out var lockExpireTime))
    {
        redisClient.UnWatch();  // since the client is scoped externally
        return false;
    }

    //If the expire time is greater than the current time then we can't let the lock go yet
    if (lockExpireTime > DateTime.UtcNow.ToUnixTimeMs())
    {
        redisClient.UnWatch();  // since the client is scoped externally
        return false;
    }

    //If the expire time is less than the current time then it wasn't released properly and we can attempt to 
    //acquire the lock. The above call to Watch(_lockKey) enrolled the key in monitoring, so if it changes
    //before we call Commit() below, the Commit will fail and return false, which means that another thread 
    //was able to acquire the lock before we finished processing.
    using (var trans = redisClient.CreateTransaction()) // we started the "Watch" above; this tx will succeed if the value has not moved 
    {
        trans.QueueCommand(r => r.Set(key, lockString));
        return trans.Commit(); //returns false if Transaction failed
    }
},timeOut);

因为StackExchange.Redis Library等效只使用string.set功能 . 尽管事实上ServiceStackRedis锁定机制更先进并且将等待并重试直到获得锁定但仍未使用REDIS SET命令的超时本身是不合理的 .

public bool LockTake(RedisKey key, RedisValue value, TimeSpan expiry, CommandFlags flags = CommandFlags.None)            {
    if (value.IsNull) throw new ArgumentNullException(nameof(value));
    return StringSet(key, value, expiry, When.NotExists, flags);
}