public LockingEngine( Func<long> timeProvider, ILogger logger, IEnumerable<LockingNode> lockingNodes, LockId lockId) { _timeProvider = timeProvider; _logger = logger; _lockId = lockId; _lockingNodes = lockingNodes; }
async static Task StartAttemptingAcquisition( LockingCoordinator lockingCoordinator, LockId lockId, ILogger logger, CancellationTokenSource lockingCancellationSource, IObserver<object> observer) { var holdingLock = false; var retryInterval = lockId.CalculateRetryInterval(); var randomGenerator = new Random(Guid.NewGuid().GetHashCode()); while (!lockingCancellationSource.IsCancellationRequested && !holdingLock) { try { holdingLock = await lockingCoordinator.TryAcquireLock(lockId).ConfigureAwait(false); if(holdingLock) { logger.ToInfoLog(string.Format("DISTRIBUTED LOCK ACQUIRED for {0}", lockId.Resource)); } else { logger.ToDebugLog("Unable to acquire the lock, retrying..."); await TaskUtils.SilentlyCanceledDelay( randomGenerator.Next(retryInterval.First(), retryInterval.Second()), lockingCancellationSource.Token) .ConfigureAwait(false); } } catch (Exception ex) { observer.OnError(ex); if(lockingCoordinator != null) await lockingCoordinator .TryReleaseTheLock(lockId) .ConfigureAwait(false); holdingLock = false; } } }
public async Task<bool> TryAcquireLock(LockId lockId) { _logger.ToDebugLog("Trying to acquire the lock..."); var startTime = _timeProvider(); var lockAcquired = await TryAcquireLockOnAllNodes(lockId); var finishTime = _timeProvider(); if (lockAcquired && lockId.HasEnoughTimeBeforeExpire(startTime, finishTime)) return lockAcquired; if (!lockAcquired) _logger.ToDebugLog("Unable to acquire the lock. Releasing all..."); else _logger.ToDebugLog("Lock correctly acquired but the time left to use it is not enough. Releasing all..."); await TryReleaseTheLock(lockId); return false; }
public Task<bool> TryReleaseTheLock(LockId lockId) { _logger.ToDebugLog("Releasing the lock..."); if (_redisClients == null || _redisClients.Count == 0) return false.FromResult(); return TryInParallelOnAllClients(async cli => await cli.Release(lockId)); }
public Task<bool> TryConfirmTheLock(LockId lockId) { return TryInParallelOnAllClients(async cli => await cli.Confirm(lockId)); }
async Task<bool> TryAcquireLockOnAllNodes(LockId lockId) { return _redisClients.Count != 0 && await TryInParallelOnAllClients(async cli => await cli.Set(lockId)); }
async Task ReleaseLock( LockingCoordinator lockingCoordinator, LockId lockId, ILogger logger, CancellationTokenSource lockingCancellationSource, IObserver<object> observer) { try { if(!lockingCancellationSource.IsCancellationRequested) lockingCancellationSource.Cancel(); observer.OnNext(new LockReleaseStarted()); logger.ToInfoLog(string.Format("Releasing the lock on {0}...", _lockId.Resource)); if(lockingCoordinator != null) await lockingCoordinator .TryReleaseTheLock(lockId) .ConfigureAwait(false); logger.ToInfoLog(string.Format("DISTRIBUTED LOCK RELEASED for {0}", _lockId.Resource)); observer.OnNext(new LockReleased()); lockingCoordinator.Dispose(); } catch (Exception ex) { observer.OnError(ex); } }