public override void Dispose()
 {
     try
     {
         using (var redisClient = DistributedLockConfig.GetRedisPoolClient())
         {
             redisClient.Remove(key);
         }
     }
     catch (Exception exp)
     {
         LogManager.DefaultLogger.Error(exp, "redis分布式尝试锁释放严重异常");
     }
 }
Пример #2
0
 public override LockResult TryGetDistributedLock(TimeSpan?getlockTimeOut, TimeSpan?taskrunTimeOut)
 {
     if (lockresult == LockResult.Success)
     {
         throw new Exception("检测到当前锁已获取");
     }
     _client = DistributedLockConfig.GetRedisPoolClient();
     //当其获取锁后,redis连接资源会一直占用,直到获取锁的资源释放后,连接才会跳出,可能会导致连接池资源的浪费。
     try
     {
         this._lock = new RedisLock(_client as RedisClient, key, getlockTimeOut);
         lockresult = LockResult.Success;
     }
     catch (Exception exp)
     {
         LogManager.DefaultLogger.Error(exp, "redis分布式尝试锁系统级别严重异常");
         lockresult = LockResult.LockSystemExceptionFailure;
     }
     return(lockresult);
 }
        public override LockResult TryGetDistributedLock(TimeSpan?getlockTimeOut, TimeSpan?taskrunTimeOut)
        {
            if (lockresult == LockResult.Success)
            {
                throw new Exception("检测到当前锁已获取");
            }
            try
            {
                using (var redisClient = DistributedLockConfig.GetRedisPoolClient())
                {
                    //内部的函数返回true,这个方法才会结束
                    ExecExtensions.RetryUntilTrue(
                        () =>
                    {
                        //SETNX 语法规则详见: http://redis.io/commands/setnx

                        //计算lock的 unix time 过期时间
                        //TimeSpan realSpan = taskrunTimeOut ?? TimeSpan.FromMilliseconds(DistributedLockConfig.MaxLockTaskRunTime);
                        TimeSpan realSpan   = taskrunTimeOut.Value;
                        DateTime expireTime = DateTime.UtcNow.Add(realSpan);
                        string lockString   = (expireTime.ToUnixTimeMs() + 1).ToString();

                        //SetEntryIfNotExists:尝试 set 锁,如果锁不存在则 set 到 redis 里,并返回true
                        var nx = redisClient.SetEntryIfNotExists(key, lockString);
                        if (nx)
                        {
                            lockresult = LockResult.Success;
                            return(true);
                        }

                        //如果锁已经存在,有可能是正确的获取,也可能是进程异常,没有正确释放锁,
                        //因此我们要检测 lock 的值(unix time),判断 lock 何时过期,否则会引起死锁

                        //监视 lock 的 key,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。
                        redisClient.Watch(key);
                        string lockExpireString = redisClient.Get <string>(key);
                        long lockExpireTime;
                        //如果 lock 的 value 不能正确转换为过期时间,则 lock 不正确,
                        //有可能是因为 lock 被其他进程改动了
                        if (!long.TryParse(lockExpireString, out lockExpireTime))
                        {
                            redisClient.UnWatch();
                            lockresult = LockResult.GetLockTimeOutFailure;
                            return(false);
                        }

                        //如果过期时间大于当前时间,则锁还未过期,当前进程不能继续执行
                        if (lockExpireTime > DateTime.UtcNow.ToUnixTimeMs())
                        {
                            redisClient.UnWatch();
                            lockresult = LockResult.GetLockTimeOutFailure;
                            return(false);
                        }

                        //如果过期时间小于当前时间,则锁没有被正常释放,之前的线程可能出现了异常
                        //在这之前用watch监视了lock的key,如果lock的值没有被改动,则当前事务将正常执行
                        using (var trans = redisClient.CreateTransaction())
                        {
                            trans.QueueCommand(r => r.Set(key, lockString));         //lockString在循环的开始会重新计算
                            var t      = trans.Commit();
                            lockresult = t == false ? LockResult.GetLockTimeOutFailure : LockResult.Success;
                            return(t);
                        }
                    },
                        getlockTimeOut
                        );
                }
            }
            catch (Exception exp)
            {
                LogManager.DefaultLogger.Error(exp, "redis分布式尝试锁系统级别严重异常");
                lockresult = LockResult.LockSystemExceptionFailure;
            }
            return(lockresult);
        }