public override void Dispose() { if (lockresult == LockResult.Success || lockresult == LockResult.LockSystemExceptionFailure) { try { long current = CurrentUnixTimeMillis(); using (var redisclient = DistributedLockConfig.GetRedisPoolClient(redisserver).GetClient()) { var v = redisclient.Get(key); if (v != null) { // 避免删除非自己获取得到的锁 if (current < BitConverter.ToInt64(v, 0)) { redisclient.Del(key); } } } } catch (Exception exp) { XXF.Log.ErrorLog.Write(string.Format("redis分布式尝试锁释放严重异常,redisserver:{0}", redisserver.NullToEmpty()), exp); } } }
public override void Dispose() { try { using (var redisClient = DistributedLockConfig.GetRedisPoolClient(redisserver).GetClient()) { redisClient.Remove(key); } } catch (Exception exp) { XXF.Log.ErrorLog.Write(string.Format("redis分布式尝试锁释放严重异常,redisserver:{0}", redisserver.NullToEmpty()), exp); } }
public override LockResult TryGetDistributedLock(TimeSpan?getlockTimeOut, TimeSpan?taskrunTimeOut) { if (lockresult == LockResult.Success) { throw new DistributedLockException("检测到当前锁已获取"); } _client = DistributedLockConfig.GetRedisPoolClient(redisserver).GetClient(); /* * 阅读源码发现当其获取锁后,redis连接资源会一直占用,知道获取锁的资源释放后,连接才会跳出,可能会导致连接池资源的浪费。 */ try { this._lock = new ServiceStack.Redis.RedisLock(_client, key, getlockTimeOut); lockresult = LockResult.Success; } catch (Exception exp) { XXF.Log.ErrorLog.Write(string.Format("redis分布式尝试锁系统级别严重异常,redisserver:{0}", redisserver.NullToEmpty()), exp); lockresult = LockResult.LockSystemExceptionFailure; } return(lockresult); }
public override LockResult TryGetDistributedLock(TimeSpan?getlockTimeOut, TimeSpan?taskrunTimeOut) { if (lockresult == LockResult.Success) { throw new DistributedLockException("检测到当前锁已获取"); } try { using (var redisClient = DistributedLockConfig.GetRedisPoolClient(redisserver).GetClient()) { ExecExtensions.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 TimeSpan realSpan = taskrunTimeOut ?? TimeSpan.FromMilliseconds(DistributedLockConfig.MaxLockTaskRunTime); //new TimeSpan(365, 0, 0, 0); //if nothing is passed in the timeout hold for a year DateTime expireTime = DateTime.UtcNow.Add(realSpan); string 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.SetEntryIfNotExists(key, lockString); if (nx) { lockresult = LockResult.Success; 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); string lockExpireString = redisClient.Get <string>(key); long lockExpireTime; if (!long.TryParse(lockExpireString, out lockExpireTime)) { redisClient.UnWatch(); // since the client is scoped externally lockresult = LockResult.GetLockTimeOutFailure; 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 lockresult = LockResult.GetLockTimeOutFailure; 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 var t = trans.Commit(); if (t == false) { lockresult = LockResult.GetLockTimeOutFailure; } else { lockresult = LockResult.Success; } return(t); } }, getlockTimeOut ); } } catch (Exception exp) { XXF.Log.ErrorLog.Write(string.Format("redis分布式尝试锁系统级别严重异常,redisserver:{0}", redisserver.NullToEmpty()), exp); lockresult = LockResult.LockSystemExceptionFailure; } return(lockresult); }
public override LockResult TryGetDistributedLock(TimeSpan?getlockTimeOut, TimeSpan?taskrunTimeOut) { if (lockresult == LockResult.Success) { throw new DistributedLockException("检测到当前锁已获取"); } try { // 1. 通过SETNX试图获取一个lock string @lock = key; long taskexpiredMilliseconds = (taskrunTimeOut != null ? (long)taskrunTimeOut.Value.TotalMilliseconds : (long)DistributedLockConfig.MaxLockTaskRunTime); long getlockexpiredMilliseconds = (getlockTimeOut != null ? (long)getlockTimeOut.Value.TotalMilliseconds : 0); long hassleepMilliseconds = 0; while (true) { using (var redisclient = DistributedLockConfig.GetRedisPoolClient(redisserver).GetClient()) { long value = CurrentUnixTimeMillis() + taskexpiredMilliseconds + 1; /*Java以前版本都是用SetNX,但是这种是无法设置超时时间的,不是很理解为什么, * 可能是因为原来的redis命令比较少导致的?现在用Add不知道效果如何. * 因对redis细节不了解,但个人怀疑若异常未释放锁经常发生,可能会导致内存逐步溢出*/ bool acquired = redisclient.Add <long>(@lock, value, TimeSpan.FromMilliseconds(taskexpiredMilliseconds + DistributedLockConfig.TaskLockDelayCleepUpTime)); //SETNX成功,则成功获取一个锁 if (acquired == true) { lockresult = LockResult.Success; } //SETNX失败,说明锁仍然被其他对象保持,检查其是否已经超时 else { var oldValueBytes = redisclient.Get(@lock); //超时 if (oldValueBytes != null && BitConverter.ToInt64(oldValueBytes, 0) < CurrentUnixTimeMillis()) { /*此处虽然重设并获取锁,但是超时时间可能被覆盖,故重设超时时间;若有进程一直在尝试获取锁,那么锁存活时间应该被延迟*/ var getValueBytes = redisclient.GetSet(@lock, BitConverter.GetBytes(value)); var o1 = redisclient.ExpireEntryIn(@lock, TimeSpan.FromMilliseconds(taskexpiredMilliseconds + DistributedLockConfig.TaskLockDelayCleepUpTime));//这里如果程序异常终止,依然会有部分锁未释放的情况。 // 获取锁成功 if (getValueBytes == oldValueBytes) { lockresult = LockResult.Success; } // 已被其他进程捷足先登了 else { lockresult = LockResult.GetLockTimeOutFailure; } } //未超时,则直接返回失败 else { lockresult = LockResult.GetLockTimeOutFailure; } } } //成功拿到锁 if (lockresult == LockResult.Success) { break; } //获取锁超时 if (hassleepMilliseconds >= getlockexpiredMilliseconds) { lockresult = LockResult.GetLockTimeOutFailure; break; } //继续等待 System.Threading.Thread.Sleep(DistributedLockConfig.GetLockFailSleepTime); hassleepMilliseconds += DistributedLockConfig.GetLockFailSleepTime; } } catch (Exception exp) { XXF.Log.ErrorLog.Write(string.Format("redis分布式尝试锁系统级别严重异常,redisserver:{0}", redisserver.NullToEmpty()), exp); lockresult = LockResult.LockSystemExceptionFailure; } return(lockresult); }