public async Task TryLockAsync_CreatesBlob_WhenItDoesNotExist() { CancellationToken cancellationToken = new CancellationToken(); RequestResult storageResult = new RequestResult { HttpStatusCode = 404 }; StorageException storageException = new StorageException(storageResult, null, null); int count = 0; _mockStorageBlob.Setup(p => p.AcquireLeaseAsync(_singletonConfig.LockPeriod, null, cancellationToken)).Returns(() => { if (count++ == 0) { throw storageException; } return(Task.FromResult(TestLeaseId)); }); _mockStorageBlob.Setup(p => p.UploadTextAsync(string.Empty, null, null, null, null, cancellationToken)).Returns(Task.FromResult(true)); _mockStorageBlob.SetupGet(p => p.Metadata).Returns(_mockBlobMetadata); _mockStorageBlob.Setup(p => p.SetMetadataAsync(It.Is <AccessCondition>(q => q.LeaseId == TestLeaseId), null, null, cancellationToken)).Returns(Task.FromResult(true)); _mockStorageBlob.Setup(p => p.ReleaseLeaseAsync(It.Is <AccessCondition>(q => q.LeaseId == TestLeaseId), null, null, cancellationToken)).Returns(Task.FromResult(true)); SingletonAttribute attribute = new SingletonAttribute(); RenewableLockHandle lockHandle = await _singletonManager.TryLockAsync(TestLockId, TestInstanceId, attribute, cancellationToken); var innerHandle = lockHandle.GetInnerHandle(); Assert.Same(_mockStorageBlob.Object, innerHandle.Blob); Assert.Equal(TestLeaseId, innerHandle.LeaseId); Assert.Equal(1, _mockStorageBlob.Object.Metadata.Keys.Count); Assert.Equal(_mockStorageBlob.Object.Metadata[BlobLeaseDistributedLockManager.FunctionInstanceMetadataKey], TestInstanceId); }
public async Task StartAsync(CancellationToken cancellationToken) { // When recovery is enabled, we don't do retries on the individual lock attempts, // since retries are being done outside bool recoveryEnabled = _singletonConfig.ListenerLockRecoveryPollingInterval != TimeSpan.MaxValue; _lockHandle = await _singletonManager.TryLockAsync(_lockId, null, _attribute, cancellationToken, retry : !recoveryEnabled); if (_lockHandle == null) { string msg = string.Format(CultureInfo.InvariantCulture, "Unable to acquire Singleton lock ({0}).", _lockId); _logger?.LogDebug(msg); // If we're unable to acquire the lock, it means another listener // has it so we return w/o starting our listener. // // However, we also start a periodic background "recovery" timer that will recheck // occasionally for the lock. This ensures that if the host that has the lock goes // down for whatever reason, others will have a chance to resume the work. if (recoveryEnabled) { LockTimer = new System.Timers.Timer(_singletonConfig.ListenerLockRecoveryPollingInterval.TotalMilliseconds); LockTimer.Elapsed += OnLockTimer; LockTimer.Start(); } return; } await _innerListener.StartAsync(cancellationToken); _isListening = true; }
public static SingletonLockHandle GetInnerHandle(this RenewableLockHandle handle) { if (handle == null) { return(null); } return((SingletonLockHandle)handle.InnerLock); }
private async Task ReleaseLockAsync(CancellationToken cancellationToken = default(CancellationToken)) { if (_lockHandle != null) { await _singletonManager.ReleaseLockAsync(_lockHandle, cancellationToken); _lockHandle = null; } }
public async Task StartAsync_StartsListener_WhenLockAcquired() { CancellationToken cancellationToken = new CancellationToken(); var lockHandle = new RenewableLockHandle(new SingletonLockHandle(), null); _mockSingletonManager.Setup(p => p.TryLockAsync(_lockId, null, _attribute, cancellationToken, false)) .ReturnsAsync(lockHandle); _mockInnerListener.Setup(p => p.StartAsync(cancellationToken)).Returns(Task.FromResult(true)); await _listener.StartAsync(cancellationToken); Assert.Null(_listener.LockTimer); _mockSingletonManager.VerifyAll(); _mockInnerListener.VerifyAll(); }
internal async Task TryAcquireLock() { _lockHandle = await _singletonManager.TryLockAsync(_lockId, null, _attribute, CancellationToken.None, retry : false); if (_lockHandle != null) { if (LockTimer != null) { LockTimer.Stop(); LockTimer.Dispose(); LockTimer = null; } await _innerListener.StartAsync(CancellationToken.None); _isListening = true; } }
public async Task Dispose_WhenLockAcquired_ReleasesLock() { CancellationToken cancellationToken = new CancellationToken(); var lockHandle = new RenewableLockHandle(new SingletonLockHandle(), null); _mockSingletonManager.Setup(p => p.TryLockAsync(_lockId, null, _attribute, cancellationToken, false)) .ReturnsAsync(lockHandle); _mockInnerListener.Setup(p => p.StartAsync(cancellationToken)).Returns(Task.FromResult(true)); await _listener.StartAsync(cancellationToken); _mockInnerListener.Setup(p => p.Dispose()); _mockSingletonManager.Setup(p => p.ReleaseLockAsync(lockHandle, cancellationToken)).Returns(Task.FromResult(true)); _listener.Dispose(); _mockSingletonManager.VerifyAll(); _mockInnerListener.VerifyAll(); }
public async Task TryAcquireLock_WhenLockAcquired_StopsLockTimerAndStartsListener() { _listener.LockTimer = new System.Timers.Timer { Interval = 30 * 1000 }; _listener.LockTimer.Start(); RenewableLockHandle lockHandle = new RenewableLockHandle(new SingletonLockHandle(), null); _mockSingletonManager.Setup(p => p.TryLockAsync(_lockId, null, _attribute, CancellationToken.None, false)) .ReturnsAsync(lockHandle); _mockInnerListener.Setup(p => p.StartAsync(CancellationToken.None)).Returns(Task.FromResult(true)); await _listener.TryAcquireLock(); Assert.Null(_listener.LockTimer); }
public async Task ReleaseLockAsync_StopsRenewalTimerAndReleasesLease() { CancellationToken cancellationToken = new CancellationToken(); Mock<ITaskSeriesTimer> mockRenewalTimer = new Mock<ITaskSeriesTimer>(MockBehavior.Strict); mockRenewalTimer.Setup(p => p.StopAsync(cancellationToken)).Returns(Task.FromResult(true)); _mockStorageBlob.Setup(p => p.ReleaseLeaseAsync(It.Is<AccessCondition>(q => q.LeaseId == TestLeaseId), null, null, cancellationToken)).Returns(Task.FromResult(true)); var handle = new RenewableLockHandle( new SingletonLockHandle { Blob = _mockStorageBlob.Object, LeaseId = TestLeaseId }, mockRenewalTimer.Object ); await _singletonManager.ReleaseLockAsync(handle, cancellationToken); mockRenewalTimer.VerifyAll(); }