public static async Task <(bool Success, string LockValue)> LockAsync(this IDatabase redisDb, string cacheKey, int timeoutSeconds = 5, bool autoDelay = true) { ArgumentCheck.NotNullOrWhiteSpace(cacheKey, nameof(cacheKey)); ArgumentCheck.NotLessThanOrEqualZero(timeoutSeconds, nameof(timeoutSeconds)); var lockKey = GetLockKey(cacheKey); var lockValue = Guid.NewGuid().ToString(); var timeoutMilliseconds = timeoutSeconds * 1000; var expiration = TimeSpan.FromMilliseconds(timeoutMilliseconds); bool flag = await redisDb.StringSetAsync(lockKey, lockValue, expiration, When.NotExists); if (flag && autoDelay) { var refreshMilliseconds = (int)(timeoutMilliseconds / 2.0); var autoDelayTimer = new Timer(timerState => Delay(redisDb, lockKey, lockValue, timeoutMilliseconds), null, refreshMilliseconds, refreshMilliseconds); var addResult = AutoDelayTimers.Instance.TryAdd(lockKey, autoDelayTimer); if (!addResult) { autoDelayTimer?.Dispose(); await redisDb.SafedUnLockAsync(lockKey, lockValue); return(false, null); } } return(flag, flag ? lockValue : null); }