public SingletonLock(string id, string functionInstanceId, SingletonAttribute attribute, SingletonManager manager) { _lockId = id; _functionInstanceId = functionInstanceId; _attribute = attribute; _singletonManager = manager; }
public SingletonListener(MethodInfo method, SingletonAttribute attribute, SingletonManager singletonManager, IListener innerListener) { _method = method; _attribute = attribute; _singletonManager = singletonManager; _innerListener = innerListener; }
public SingletonValueProvider(MethodInfo method, string scope, string functionInstanceId, SingletonAttribute attribute, SingletonManager singletonManager) { _scope = string.IsNullOrEmpty(scope) ? "default" : scope; string lockId = SingletonManager.FormatLockId(method, scope); _singletonLock = new SingletonLock(lockId, functionInstanceId, attribute, singletonManager); _watcher = new SingletonWatcher(_singletonLock); }
public SingletonValueProviderTests() { _attribute = new SingletonAttribute("TestScope"); SingletonManager singletonManager = new SingletonManager(null, null, null, null, new FixedHostIdProvider(TestHostId)); _method = GetType().GetMethod("TestJob", BindingFlags.Static | BindingFlags.Public); _lockId = SingletonManager.FormatLockId(_method, SingletonScope.Function, TestHostId, _attribute.ScopeId); _valueProvider = new SingletonValueProvider(_method, "TestScope", TestInstanceId, _attribute, singletonManager); }
public SingletonValueProviderTests() { _attribute = new SingletonAttribute("TestScope"); SingletonManager singletonManager = new SingletonManager(); _method = GetType().GetMethod("TestJob", BindingFlags.Static | BindingFlags.Public); _lockId = SingletonManager.FormatLockId(_method, _attribute.Scope); _valueProvider = new SingletonValueProvider(_method, "TestScope", TestInstanceId, _attribute, singletonManager); }
public SingletonListener(MethodInfo method, SingletonAttribute attribute, SingletonManager singletonManager, IListener innerListener) { _attribute = attribute; _singletonManager = singletonManager; _singletonConfig = _singletonManager.Config; _innerListener = innerListener; string boundScopeId = _singletonManager.GetBoundScopeId(_attribute.ScopeId); _lockId = singletonManager.FormatLockId(method, _attribute.Scope, boundScopeId); _lockId += ".Listener"; }
public void ToInvokeString_ReturnsExpectedValue() { SingletonAttribute attribute = new SingletonAttribute(); SingletonValueProvider localValueProvider = new SingletonValueProvider(_method, attribute.Scope, TestInstanceId, attribute, new SingletonManager()); SingletonLock singletonLock = (SingletonLock)localValueProvider.GetValue(); Assert.Equal("Scope: default", localValueProvider.ToInvokeString()); attribute = new SingletonAttribute(@"{Region}\{Zone}"); localValueProvider = new SingletonValueProvider(_method, @"Central\3", TestInstanceId, attribute, new SingletonManager()); singletonLock = (SingletonLock)localValueProvider.GetValue(); Assert.Equal(@"Scope: Central\3", localValueProvider.ToInvokeString()); }
public void Constructor_SetsExpectedValues() { SingletonAttribute attribute = new SingletonAttribute(); Mock<SingletonManager> mockSingletonManager = new Mock<SingletonManager>(MockBehavior.Strict); SingletonLock singletonLock = new SingletonLock(TestLockId, TestInstanceId, attribute, mockSingletonManager.Object); Assert.Equal(TestLockId, singletonLock.Id); Assert.Equal(TestInstanceId, singletonLock.FunctionId); Assert.Null(singletonLock.AcquireStartTime); Assert.Null(singletonLock.AcquireEndTime); Assert.Null(singletonLock.ReleaseTime); }
public async Task GetOwnerAsync_InvokesSingletonManager_WithExpectedValues() { CancellationToken cancellationToken = new CancellationToken(); SingletonAttribute attribute = new SingletonAttribute(); Mock<SingletonManager> mockSingletonManager = new Mock<SingletonManager>(MockBehavior.Strict); string lockOwner = "ownerid"; mockSingletonManager.Setup(p => p.GetLockOwnerAsync(TestLockId, cancellationToken)).ReturnsAsync(lockOwner); SingletonLock singletonLock = new SingletonLock(TestLockId, TestInstanceId, attribute, mockSingletonManager.Object); await singletonLock.GetOwnerAsync(cancellationToken); }
public async virtual Task<object> TryLockAsync(string lockId, string functionInstanceId, SingletonAttribute attribute, CancellationToken cancellationToken) { IStorageBlockBlob lockBlob = _directory.GetBlockBlobReference(lockId); await TryCreateAsync(lockBlob, cancellationToken); _trace.Verbose(string.Format(CultureInfo.InvariantCulture, "Waiting for Singleton lock ({0})", lockId), source: TraceSource.Execution); string leaseId = await TryAcquireLeaseAsync(lockBlob, _config.LockPeriod, cancellationToken); if (string.IsNullOrEmpty(leaseId)) { // Someone else has the lease. Continue trying to periodically get the lease for // a period of time TimeSpan acquisitionTimeout = attribute.LockAcquisitionTimeout != null ? TimeSpan.FromSeconds(attribute.LockAcquisitionTimeout.Value) : _config.LockAcquisitionTimeout; double remainingWaitTime = acquisitionTimeout.TotalMilliseconds; while (string.IsNullOrEmpty(leaseId) && remainingWaitTime > 0) { await Task.Delay(_config.LockAcquisitionPollingInterval); leaseId = await TryAcquireLeaseAsync(lockBlob, _config.LockPeriod, cancellationToken); remainingWaitTime -= _config.LockAcquisitionPollingInterval.TotalMilliseconds; } } if (string.IsNullOrEmpty(leaseId)) { _trace.Verbose(string.Format(CultureInfo.InvariantCulture, "Unable to acquire Singleton lock ({0}).", lockId), source: TraceSource.Execution); return null; } _trace.Verbose(string.Format(CultureInfo.InvariantCulture, "Singleton lock acquired ({0})", lockId), source: TraceSource.Execution); if (!string.IsNullOrEmpty(functionInstanceId)) { await WriteLeaseBlobMetadata(lockBlob, leaseId, functionInstanceId, cancellationToken); } SingletonLockHandle lockHandle = new SingletonLockHandle { LeaseId = leaseId, LockId = lockId, Blob = lockBlob, LeaseRenewalTimer = CreateLeaseRenewalTimer(lockBlob, leaseId, lockId, _config.LockPeriod, _backgroundExceptionDispatcher) }; // start the renewal timer, which ensures that we maintain our lease until // the lock is released lockHandle.LeaseRenewalTimer.Start(); return lockHandle; }
public SingletonListenerTests() { MethodInfo methodInfo = this.GetType().GetMethod("TestJob", BindingFlags.Static|BindingFlags.NonPublic); _attribute = new SingletonAttribute(); _config = new SingletonConfiguration { LockPeriod = TimeSpan.FromSeconds(20) }; _mockSingletonManager = new Mock<SingletonManager>(MockBehavior.Strict, null, null, null, null, new FixedHostIdProvider(TestHostId), null); _mockSingletonManager.SetupGet(p => p.Config).Returns(_config); _mockInnerListener = new Mock<IListener>(MockBehavior.Strict); _listener = new SingletonListener(methodInfo, _attribute, _mockSingletonManager.Object, _mockInnerListener.Object); _lockId = SingletonManager.FormatLockId(methodInfo, SingletonScope.Function, TestHostId, _attribute.ScopeId) + ".Listener"; }
public async virtual Task<object> LockAsync(string lockId, string functionInstanceId, SingletonAttribute attribute, CancellationToken cancellationToken) { object lockHandle = await TryLockAsync(lockId, functionInstanceId, attribute, cancellationToken); if (lockHandle == null) { TimeSpan acquisitionTimeout = attribute.LockAcquisitionTimeout != null ? TimeSpan.FromSeconds(attribute.LockAcquisitionTimeout.Value) : _config.LockAcquisitionTimeout; throw new TimeoutException(string.Format("Unable to acquire singleton lock blob lease for blob '{0}' (timeout of {1} exceeded).", lockId, acquisitionTimeout.ToString("g"))); } return lockHandle; }
public async Task TryLockAsync_CreatesBlobLease_WithAutoRenewal() { CancellationToken cancellationToken = new CancellationToken(); _mockStorageBlob.SetupGet(p => p.Metadata).Returns(_mockBlobMetadata); _mockStorageBlob.Setup(p => p.UploadTextAsync(string.Empty, null, It.Is<AccessCondition>(q => q.IfNoneMatchETag == "*"), null, null, cancellationToken)).Returns(Task.FromResult(true)); _mockStorageBlob.Setup(p => p.AcquireLeaseAsync(_singletonConfig.LockPeriod, null, cancellationToken)).ReturnsAsync(TestLeaseId); _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)); int renewCount = 0; _mockStorageBlob.Setup(p => p.RenewLeaseAsync(It.Is<AccessCondition>(q => q.LeaseId == TestLeaseId), null, null, It.IsAny<CancellationToken>())) .Callback<AccessCondition, BlobRequestOptions, OperationContext, CancellationToken>( (mockAccessCondition, mockOptions, mockContext, mockCancellationToken) => { renewCount++; }).Returns(Task.FromResult(true)); SingletonAttribute attribute = new SingletonAttribute(); SingletonManager.SingletonLockHandle lockHandle = (SingletonManager.SingletonLockHandle)await _singletonManager.TryLockAsync(TestLockId, TestInstanceId, attribute, cancellationToken); Assert.Same(_mockStorageBlob.Object, lockHandle.Blob); Assert.Equal(TestLeaseId, lockHandle.LeaseId); Assert.Equal(1, _mockStorageBlob.Object.Metadata.Keys.Count); Assert.Equal(_mockStorageBlob.Object.Metadata[SingletonManager.FunctionInstanceMetadataKey], TestInstanceId); // wait for enough time that we expect some lease renewals to occur int duration = 2000; int expectedRenewalCount = (int)(duration / (_singletonConfig.LockPeriod.TotalMilliseconds / 2)) - 1; await Task.Delay(duration); Assert.Equal(expectedRenewalCount, renewCount); // now release the lock and verify no more renewals await _singletonManager.ReleaseLockAsync(lockHandle, cancellationToken); // verify the traces Assert.Equal(1, _trace.Traces.Count(p => p.Contains("Verbose WebJobs.Execution Waiting for Singleton lock (testid)"))); Assert.Equal(1, _trace.Traces.Count(p => p.Contains("Verbose WebJobs.Execution Singleton lock acquired (testid)"))); Assert.Equal(renewCount, _trace.Traces.Count(p => p.Contains("Renewing Singleton lock (testid)"))); Assert.Equal(1, _trace.Traces.Count(p => p.Contains("Verbose WebJobs.Execution Singleton lock released (testid)"))); renewCount = 0; await Task.Delay(1000); Assert.Equal(0, renewCount); _mockStorageBlob.VerifyAll(); }
public async Task AquireAsync_InvokesSingletonManager_WithExpectedValues() { CancellationToken cancellationToken = new CancellationToken(); SingletonAttribute attribute = new SingletonAttribute(); SingletonManager.SingletonLockHandle handle = new SingletonManager.SingletonLockHandle(); Mock<SingletonManager> mockSingletonManager = new Mock<SingletonManager>(MockBehavior.Strict); mockSingletonManager.Setup(p => p.LockAsync(TestLockId, TestInstanceId, attribute, cancellationToken)).ReturnsAsync(handle); SingletonLock singletonLock = new SingletonLock(TestLockId, TestInstanceId, attribute, mockSingletonManager.Object); Assert.False(singletonLock.IsHeld); await singletonLock.AcquireAsync(cancellationToken); Assert.NotNull(singletonLock.AcquireStartTime); Assert.NotNull(singletonLock.AcquireEndTime); Assert.True(singletonLock.IsHeld); }
public async virtual Task <object> TryLockAsync(string lockId, string functionInstanceId, SingletonAttribute attribute, CancellationToken cancellationToken, bool retry = true) { _trace.Verbose(string.Format(CultureInfo.InvariantCulture, "Waiting for Singleton lock ({0})", lockId), source: TraceSource.Execution); IStorageBlobDirectory lockDirectory = GetLockDirectory(attribute.Account); IStorageBlockBlob lockBlob = lockDirectory.GetBlockBlobReference(lockId); TimeSpan lockPeriod = GetLockPeriod(attribute, _config); string leaseId = await TryAcquireLeaseAsync(lockBlob, lockPeriod, cancellationToken); if (string.IsNullOrEmpty(leaseId) && retry) { // Someone else has the lease. Continue trying to periodically get the lease for // a period of time TimeSpan acquisitionTimeout = attribute.LockAcquisitionTimeout != null ? TimeSpan.FromSeconds(attribute.LockAcquisitionTimeout.Value) : _config.LockAcquisitionTimeout; TimeSpan timeWaited = TimeSpan.Zero; while (string.IsNullOrEmpty(leaseId) && (timeWaited < acquisitionTimeout)) { await Task.Delay(_config.LockAcquisitionPollingInterval); timeWaited += _config.LockAcquisitionPollingInterval; leaseId = await TryAcquireLeaseAsync(lockBlob, lockPeriod, cancellationToken); } } if (string.IsNullOrEmpty(leaseId)) { _trace.Verbose(string.Format(CultureInfo.InvariantCulture, "Unable to acquire Singleton lock ({0}).", lockId), source: TraceSource.Execution); return(null); } _trace.Verbose(string.Format(CultureInfo.InvariantCulture, "Singleton lock acquired ({0})", lockId), source: TraceSource.Execution); if (!string.IsNullOrEmpty(functionInstanceId)) { await WriteLeaseBlobMetadata(lockBlob, leaseId, functionInstanceId, cancellationToken); } SingletonLockHandle lockHandle = new SingletonLockHandle { LeaseId = leaseId, LockId = lockId, Blob = lockBlob, LeaseRenewalTimer = CreateLeaseRenewalTimer(lockBlob, leaseId, lockId, lockPeriod, _exceptionHandler) }; // start the renewal timer, which ensures that we maintain our lease until // the lock is released lockHandle.LeaseRenewalTimer.Start(); return(lockHandle); }
public async virtual Task <object> LockAsync(string lockId, string functionInstanceId, SingletonAttribute attribute, CancellationToken cancellationToken) { object lockHandle = await TryLockAsync(lockId, functionInstanceId, attribute, cancellationToken); if (lockHandle == null) { TimeSpan acquisitionTimeout = attribute.LockAcquisitionTimeout != null ? TimeSpan.FromSeconds(attribute.LockAcquisitionTimeout.Value) : _config.LockAcquisitionTimeout; throw new TimeoutException(string.Format("Unable to acquire singleton lock blob lease for blob '{0}' (timeout of {1} exceeded).", lockId, acquisitionTimeout.ToString("g"))); } return(lockHandle); }
private async Task <IReadOnlyDictionary <string, IValueProvider> > BindCoreAsync(ValueBindingContext context, object value, IDictionary <string, object> parameters) { Dictionary <string, IValueProvider> valueProviders = new Dictionary <string, IValueProvider>(); IValueProvider triggerProvider; IReadOnlyDictionary <string, object> bindingData; try { ITriggerData triggerData = await _triggerBinding.BindAsync(value, context); triggerProvider = triggerData.ValueProvider; bindingData = triggerData.BindingData; } catch (OperationCanceledException) { throw; } catch (Exception exception) { triggerProvider = new BindingExceptionValueProvider(_triggerParameterName, exception); bindingData = null; } valueProviders.Add(_triggerParameterName, triggerProvider); BindingContext bindingContext = FunctionBinding.NewBindingContext(context, bindingData, parameters); // Bind Singleton if specified SingletonAttribute singletonAttribute = SingletonManager.GetFunctionSingletonOrNull(_descriptor, isTriggered: true); if (singletonAttribute != null) { string boundScopeId = _singletonManager.GetBoundScopeId(singletonAttribute.ScopeId, bindingData); IValueProvider singletonValueProvider = new SingletonValueProvider(_descriptor.Method, boundScopeId, context.FunctionInstanceId.ToString(), singletonAttribute, _singletonManager); valueProviders.Add(SingletonValueProvider.SingletonParameterName, singletonValueProvider); } foreach (KeyValuePair <string, IBinding> item in _nonTriggerBindings) { string name = item.Key; IBinding binding = item.Value; IValueProvider valueProvider; try { if (parameters != null && parameters.ContainsKey(name)) { valueProvider = await binding.BindAsync(parameters[name], context); } else { valueProvider = await binding.BindAsync(bindingContext); } } catch (OperationCanceledException) { throw; } catch (Exception exception) { valueProvider = new BindingExceptionValueProvider(name, exception); } valueProviders.Add(name, valueProvider); } return(valueProviders); }
public async virtual Task <RenewableLockHandle> TryLockAsync(string lockId, string functionInstanceId, SingletonAttribute attribute, CancellationToken cancellationToken, bool retry = true) { TimeSpan lockPeriod = GetLockPeriod(attribute, _config); IDistributedLock handle = await _lockManager.TryLockAsync(attribute.Account, lockId, functionInstanceId, null, lockPeriod, cancellationToken); if ((handle == null) && retry) { // Someone else has the lease. Continue trying to periodically get the lease for // a period of time TimeSpan acquisitionTimeout = GetLockAcquisitionTimeout(attribute, _config); TimeSpan timeWaited = TimeSpan.Zero; while ((handle == null) && (timeWaited < acquisitionTimeout)) { await Task.Delay(_config.LockAcquisitionPollingInterval); timeWaited += _config.LockAcquisitionPollingInterval; handle = await _lockManager.TryLockAsync(attribute.Account, lockId, functionInstanceId, null, lockPeriod, cancellationToken); } } if (handle == null) { return(null); } var renewal = CreateLeaseRenewalTimer(lockPeriod, handle); // start the renewal timer, which ensures that we maintain our lease until // the lock is released renewal.Start(); string msg = string.Format(CultureInfo.InvariantCulture, "Singleton lock acquired ({0})", lockId); _logger?.LogDebug(msg); return(new RenewableLockHandle(handle, renewal)); }
public async Task LockAsync_WithContention_AcquisitionTimeoutExpires_Throws() { CancellationToken cancellationToken = new CancellationToken(); int count = 0; _mockStorageBlob.Setup(p => p.AcquireLeaseAsync(_singletonConfig.LockPeriod, null, cancellationToken)) .Callback<TimeSpan?, string, CancellationToken>((mockPeriod, mockLeaseId, mockCancellationToken) => { ++count; }).Returns(() => { return Task.FromResult<string>(null); }); SingletonAttribute attribute = new SingletonAttribute(); TimeoutException exception = await Assert.ThrowsAsync<TimeoutException>(async () => await _singletonManager.LockAsync(TestLockId, TestInstanceId, attribute, cancellationToken)); int expectedRetryCount = (int)(_singletonConfig.LockAcquisitionTimeout.TotalMilliseconds / _singletonConfig.LockAcquisitionPollingInterval.TotalMilliseconds); Assert.Equal(expectedRetryCount, count - 1); Assert.Equal("Unable to acquire singleton lock blob lease for blob 'testid' (timeout of 0:00:00.2 exceeded).", exception.Message); _mockStorageBlob.VerifyAll(); }
private async Task <IReadOnlyDictionary <string, IValueProvider> > BindCoreAsync(ValueBindingContext context, object value, IDictionary <string, object> parameters) { Dictionary <string, IValueProvider> valueProviders = new Dictionary <string, IValueProvider>(); IValueProvider triggerProvider; IReadOnlyDictionary <string, object> bindingData; IValueBinder triggerReturnValueProvider = null; try { ITriggerData triggerData = await _triggerBinding.BindAsync(value, context); triggerProvider = triggerData.ValueProvider; bindingData = triggerData.BindingData; triggerReturnValueProvider = (triggerData as TriggerData)?.ReturnValueProvider; } catch (OperationCanceledException) { throw; } catch (Exception exception) { triggerProvider = new BindingExceptionValueProvider(_triggerParameterName, exception); bindingData = null; } valueProviders.Add(_triggerParameterName, triggerProvider); // Bind Singleton if specified SingletonAttribute singletonAttribute = SingletonManager.GetFunctionSingletonOrNull(_descriptor, isTriggered: true); if (singletonAttribute != null) { string boundScopeId = _singletonManager.GetBoundScopeId(singletonAttribute.ScopeId, bindingData); IValueProvider singletonValueProvider = new SingletonValueProvider(_descriptor, boundScopeId, context.FunctionInstanceId.ToString(), singletonAttribute, _singletonManager); valueProviders.Add(SingletonValueProvider.SingletonParameterName, singletonValueProvider); } BindingContext bindingContext = FunctionBinding.NewBindingContext(context, bindingData, parameters); foreach (KeyValuePair <string, IBinding> item in _nonTriggerBindings) { string name = item.Key; IBinding binding = item.Value; IValueProvider valueProvider; try { if (parameters != null && parameters.ContainsKey(name)) { valueProvider = await binding.BindAsync(parameters[name], context); } else { valueProvider = await binding.BindAsync(bindingContext); } } catch (OperationCanceledException) { throw; } catch (Exception exception) { valueProvider = new BindingExceptionValueProvider(name, exception); } valueProviders.Add(name, valueProvider); } // Triggers can optionally process the return values of functions. They do so by declaring // a "$return" key in their binding data dictionary and mapping it to an IValueBinder. // An explicit return binding takes precedence over an implicit trigger binding. if (!valueProviders.ContainsKey(FunctionIndexer.ReturnParamName)) { if (triggerReturnValueProvider != null) { valueProviders.Add(FunctionIndexer.ReturnParamName, triggerReturnValueProvider); } } return(valueProviders); }
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(); SingletonManager.SingletonLockHandle lockHandle = (SingletonManager.SingletonLockHandle)await _singletonManager.TryLockAsync(TestLockId, TestInstanceId, attribute, cancellationToken); Assert.Same(_mockStorageBlob.Object, lockHandle.Blob); Assert.Equal(TestLeaseId, lockHandle.LeaseId); Assert.Equal(1, _mockStorageBlob.Object.Metadata.Keys.Count); Assert.Equal(_mockStorageBlob.Object.Metadata[SingletonManager.FunctionInstanceMetadataKey], TestInstanceId); }
public void ValidateSingletonAttribute_ScopeIsHost_ModeIsListener_Throws() { SingletonAttribute attribute = new SingletonAttribute("TestScope", SingletonScope.Host); InvalidOperationException exception = Assert.Throws<InvalidOperationException>(() => { SingletonManager.ValidateSingletonAttribute(attribute, SingletonMode.Listener); }); Assert.Equal("Scope 'Host' cannot be used when the mode is set to 'Listener'.", exception.Message); }
public async Task GetLockOwnerAsync_LeaseAvailable_ReturnsNull() { CancellationToken cancellationToken = new CancellationToken(); _mockStorageBlob.Setup(p => p.FetchAttributesAsync(cancellationToken)).Returns(Task.FromResult(true)); Mock<IStorageBlobProperties> mockBlobProperties = new Mock<IStorageBlobProperties>(MockBehavior.Strict); mockBlobProperties.Setup(p => p.LeaseState).Returns(LeaseState.Available); mockBlobProperties.Setup(p => p.LeaseStatus).Returns(LeaseStatus.Unlocked); _mockStorageBlob.SetupGet(p => p.Properties).Returns(mockBlobProperties.Object); SingletonAttribute attribute = new SingletonAttribute(); string lockOwner = await _singletonManager.GetLockOwnerAsync(attribute, TestLockId, CancellationToken.None); Assert.Equal(null, lockOwner); mockBlobProperties.VerifyAll(); _mockStorageBlob.VerifyAll(); }
// Wrapper to get the internal class. public static async Task<SingletonLockHandle> TryLockInternalAsync(this SingletonManager manager, string lockId, string functionInstanceId, SingletonAttribute attribute, CancellationToken cancellationToken, bool retry = true) { var handle = await manager.TryLockAsync(lockId, functionInstanceId, attribute, cancellationToken, retry); return handle.GetInnerHandle(); }
public async Task TryLockAsync_WithContention_PollsForLease() { CancellationToken cancellationToken = new CancellationToken(); _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)); int numRetries = 3; int count = 0; _mockStorageBlob.Setup(p => p.AcquireLeaseAsync(_singletonConfig.LockPeriod, null, cancellationToken)) .Returns(() => { count++; return Task.FromResult<string>(count > numRetries ? TestLeaseId : null); }); SingletonAttribute attribute = new SingletonAttribute(); SingletonManager.SingletonLockHandle lockHandle = (SingletonManager.SingletonLockHandle)await _singletonManager.TryLockAsync(TestLockId, TestInstanceId, attribute, cancellationToken); Assert.NotNull(lockHandle); Assert.Equal(TestLeaseId, lockHandle.LeaseId); Assert.Equal(numRetries, count - 1); Assert.NotNull(lockHandle.LeaseRenewalTimer); _mockStorageBlob.VerifyAll(); }
internal static TimeSpan GetLockPeriod(SingletonAttribute attribute, SingletonConfiguration config) { return attribute.Mode == SingletonMode.Listener ? config.ListenerLockPeriod : config.LockPeriod; }
public async Task TryLockAsync_WithContention_NoRetry_DoesNotPollForLease() { CancellationToken cancellationToken = new CancellationToken(); int count = 0; _mockStorageBlob.Setup(p => p.AcquireLeaseAsync(_singletonConfig.LockPeriod, null, cancellationToken)) .Returns(() => { count++; return Task.FromResult<string>(null); }); SingletonAttribute attribute = new SingletonAttribute(); SingletonManager.SingletonLockHandle lockHandle = (SingletonManager.SingletonLockHandle) await _singletonManager.TryLockAsync(TestLockId, TestInstanceId, attribute, cancellationToken, retry: false); Assert.Null(lockHandle); Assert.Equal(1, count); _mockStorageBlob.VerifyAll(); }
public void disabled_singletons_are_ignored() { var singletonType = typeof(object); // Anything will do here. var mockReflection = new Mock<IReflection>(); mockReflection .Setup(m => m.FindTypesMarkedByAttributes(new Type[] { typeof(SingletonAttribute) })) .Returns(new Type[] { singletonType }); var testSingletonAttribute = new SingletonAttribute(() => false); mockReflection .Setup(m => m.GetAttributes<SingletonAttribute>(singletonType)) .Returns(new SingletonAttribute[] { testSingletonAttribute }); ; var mockLogger = new Mock<ILogger>(); var mockSingletonManager = new Mock<ISingletonManager>(); var testObject = new SingletonScanner(mockReflection.Object, mockLogger.Object, mockSingletonManager.Object); testObject.ScanSingletonTypes(); mockSingletonManager.Verify(m => m.RegisterSingleton(It.IsAny<SingletonDef>()), Times.Never()); }
public async Task GetLockOwnerAsync_LeaseLocked_ReturnsOwner() { CancellationToken cancellationToken = new CancellationToken(); _mockStorageBlob.SetupGet(p => p.Metadata).Returns(_mockBlobMetadata); _mockStorageBlob.Setup(p => p.FetchAttributesAsync(cancellationToken)).Returns(Task.FromResult(true)); Mock<IStorageBlobProperties> mockBlobProperties = new Mock<IStorageBlobProperties>(MockBehavior.Strict); mockBlobProperties.Setup(p => p.LeaseState).Returns(LeaseState.Leased); _mockStorageBlob.SetupGet(p => p.Properties).Returns(mockBlobProperties.Object); SingletonAttribute attribute = new SingletonAttribute(); string lockOwner = await _singletonManager.GetLockOwnerAsync(attribute, TestLockId, CancellationToken.None); Assert.Equal(null, lockOwner); _mockBlobMetadata.Add(SingletonManager.FunctionInstanceMetadataKey, TestLockId); lockOwner = await _singletonManager.GetLockOwnerAsync(attribute, TestLockId, CancellationToken.None); Assert.Equal(TestLockId, lockOwner); mockBlobProperties.VerifyAll(); _mockStorageBlob.VerifyAll(); }
internal static TimeSpan GetLockPeriod(SingletonAttribute attribute, SingletonConfiguration config) { return(attribute.Mode == SingletonMode.Listener ? config.ListenerLockPeriod : config.LockPeriod); }
public void ValidateSingletonAttribute_ScopeIsHost_ScopeIdEmpty_Throws(SingletonMode mode) { SingletonAttribute attribute = new SingletonAttribute(null, SingletonScope.Host); InvalidOperationException exception = Assert.Throws<InvalidOperationException>(() => { SingletonManager.ValidateSingletonAttribute(attribute, mode); }); Assert.Equal("A ScopeId value must be provided when using scope 'Host'.", exception.Message); }
/// <summary> /// Creates and returns singleton listener scoped to the host. /// </summary> /// <param name="innerListener">The inner listener to wrap.</param> /// <param name="scopeId">The scope ID to use.</param> /// <returns>The singleton listener.</returns> public SingletonListener CreateHostSingletonListener(IListener innerListener, string scopeId) { SingletonAttribute singletonAttribute = new SingletonAttribute(scopeId, SingletonScope.Host) { Mode = SingletonMode.Listener }; return new SingletonListener(null, singletonAttribute, this, innerListener); }
public void GetLockPeriod_ReturnsExpectedValue() { SingletonAttribute attribute = new SingletonAttribute { Mode = SingletonMode.Listener }; SingletonConfiguration config = new SingletonConfiguration() { LockPeriod = TimeSpan.FromSeconds(16), ListenerLockPeriod = TimeSpan.FromSeconds(17) }; TimeSpan value = SingletonManager.GetLockPeriod(attribute, config); Assert.Equal(config.ListenerLockPeriod, value); attribute.Mode = SingletonMode.Function; value = SingletonManager.GetLockPeriod(attribute, config); Assert.Equal(config.LockPeriod, value); }
internal static void ValidateSingletonAttribute(SingletonAttribute attribute, SingletonMode mode) { if (attribute.Scope == SingletonScope.Host && string.IsNullOrEmpty(attribute.ScopeId)) { throw new InvalidOperationException("A ScopeId value must be provided when using scope 'Host'."); } if (mode == SingletonMode.Listener && attribute.Scope == SingletonScope.Host) { throw new InvalidOperationException("Scope 'Host' cannot be used when the mode is set to 'Listener'."); } }
public async virtual Task<string> GetLockOwnerAsync(SingletonAttribute attribute, string lockId, CancellationToken cancellationToken) { IStorageBlobDirectory lockDirectory = GetLockDirectory(attribute.Account); IStorageBlockBlob lockBlob = lockDirectory.GetBlockBlobReference(lockId); await ReadLeaseBlobMetadata(lockBlob, cancellationToken); // if the lease is Available, then there is no current owner // (any existing owner value is the last owner that held the lease) if (lockBlob.Properties.LeaseState == LeaseState.Available && lockBlob.Properties.LeaseStatus == LeaseStatus.Unlocked) { return null; } string owner = string.Empty; lockBlob.Metadata.TryGetValue(FunctionInstanceMetadataKey, out owner); return owner; }
public async virtual Task <string> GetLockOwnerAsync(SingletonAttribute attribute, string lockId, CancellationToken cancellationToken) { return(await _lockManager.GetLockOwnerAsync(attribute.Account, lockId, cancellationToken)); }