コード例 #1
0
 public SingletonLock(string id, string functionInstanceId, SingletonAttribute attribute, SingletonManager manager)
 {
     _lockId = id;
     _functionInstanceId = functionInstanceId;
     _attribute = attribute;
     _singletonManager = manager;
 }
コード例 #2
0
 public SingletonListener(MethodInfo method, SingletonAttribute attribute, SingletonManager singletonManager, IListener innerListener)
 {
     _method = method;
     _attribute = attribute;
     _singletonManager = singletonManager;
     _innerListener = innerListener;
 }
コード例 #3
0
 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);
 }
コード例 #4
0
 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);
 }
コード例 #5
0
 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);
 }
コード例 #6
0
        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";
        }
コード例 #7
0
        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());
        }
コード例 #8
0
        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);
        }
コード例 #9
0
        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);
        }
コード例 #10
0
        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;
        }
コード例 #11
0
 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";
 }
コード例 #12
0
        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;
        }
コード例 #13
0
        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();
        }
コード例 #14
0
        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);
        }
コード例 #15
0
        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);
        }
コード例 #16
0
        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);
        }
コード例 #17
0
        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);
        }
コード例 #18
0
        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));
        }
コード例 #19
0
        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();
        }
コード例 #20
0
        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);
        }
コード例 #21
0
        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);
        }
コード例 #22
0
        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);

        }
コード例 #23
0
        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();
        }
コード例 #24
0
 // 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();
 }
コード例 #25
0
        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();
        }
コード例 #26
0
 internal static TimeSpan GetLockPeriod(SingletonAttribute attribute, SingletonConfiguration config)
 {
     return attribute.Mode == SingletonMode.Listener ?
             config.ListenerLockPeriod : config.LockPeriod;
 }
コード例 #27
0
        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();
        }
コード例 #28
0
        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());
        }
コード例 #29
0
        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();
        }
コード例 #30
0
 internal static TimeSpan GetLockPeriod(SingletonAttribute attribute, SingletonConfiguration config)
 {
     return(attribute.Mode == SingletonMode.Listener ?
            config.ListenerLockPeriod : config.LockPeriod);
 }
コード例 #31
0
        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);
        }
コード例 #32
0
 /// <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);
 }
コード例 #33
0
        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);
        }
コード例 #34
0
        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'.");
            }
        }
コード例 #35
0
        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;
        }
コード例 #36
0
 public async virtual Task <string> GetLockOwnerAsync(SingletonAttribute attribute, string lockId, CancellationToken cancellationToken)
 {
     return(await _lockManager.GetLockOwnerAsync(attribute.Account, lockId, cancellationToken));
 }