public async Task ReleaseAsync_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); mockSingletonManager.Setup(p => p.ReleaseLockAsync(handle, cancellationToken)).Returns(Task.FromResult(true)); SingletonLock singletonLock = new SingletonLock(TestLockId, TestInstanceId, attribute, mockSingletonManager.Object); Assert.False(singletonLock.IsHeld); await singletonLock.AcquireAsync(cancellationToken); Assert.True(singletonLock.IsHeld); await singletonLock.ReleaseAsync(cancellationToken); Assert.False(singletonLock.IsHeld); Assert.NotNull(singletonLock.AcquireStartTime); Assert.NotNull(singletonLock.AcquireEndTime); Assert.NotNull(singletonLock.ReleaseTime); }
public async Task GetValueAsync_ReturnsExpectedValue() { SingletonLock value = (SingletonLock)(await _valueProvider.GetValueAsync()); Assert.Equal(_lockId, value.Id); Assert.Equal(TestInstanceId, value.FunctionId); }
public void GetValue_ReturnsExpectedValue() { SingletonLock value = (SingletonLock)_valueProvider.GetValue(); Assert.Equal(_lockId, value.Id); Assert.Equal(TestInstanceId, value.FunctionId); }
public static SingletonLock GetInstance() { lock (myLock) { if (myInstance == null) { myInstance = new SingletonLock(); } return(myInstance); } }
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); }
private static async Task <SingletonLock> GetSingletonLockAsync(IReadOnlyDictionary <string, IValueProvider> parameters) { IValueProvider singletonValueProvider = null; SingletonLock singleton = null; if (parameters.TryGetValue(SingletonValueProvider.SingletonParameterName, out singletonValueProvider)) { singleton = (SingletonLock)(await singletonValueProvider.GetValueAsync()); } return(singleton); }
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 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 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 static void Run() { char key; while (true) { printMenu(); key = Console.ReadKey().KeyChar; Console.WriteLine(); switch (key) { case 'f': FactoryMethodPatternExample.Display(); break; case 'a': AbstractFactoryPatternExample.Display(); break; case 's': SingletonPatternExample.Display(); SingletonLock.Display(); SingletonThreads.Display(); break; case 'l': SingletonStaticFields.Display(); SingletonNestedClass.Display(); SingletonNestedLazy.Display(); break; case 'z': SingletonLazy.Display(); break; case 'p': PrototypePatternExample.Display(); PrototypePatternExampleComplex.Display(); break; case 'b': BuilderPatternExample.Display(); break; case 'x': return; } Console.ReadKey(); } }
public async Task ToInvokeString_ReturnsExpectedValue() { SingletonManager singletonManager = new SingletonManager(null, null, null, null, null, new FixedHostIdProvider(TestHostId)); SingletonAttribute attribute = new SingletonAttribute(); SingletonValueProvider localValueProvider = new SingletonValueProvider(_method, attribute.ScopeId, TestInstanceId, attribute, singletonManager); SingletonLock singletonLock = (SingletonLock)(await localValueProvider.GetValueAsync()); Assert.Equal("ScopeId: (null)", localValueProvider.ToInvokeString()); attribute = new SingletonAttribute(@"{Region}\{Zone}"); localValueProvider = new SingletonValueProvider(_method, @"Central\3", TestInstanceId, attribute, singletonManager); singletonLock = (SingletonLock)(await localValueProvider.GetValueAsync()); Assert.Equal(@"ScopeId: Central\3", localValueProvider.ToInvokeString()); }
public static SingletonLock GetSingleton() { if (s_singleton == null) { lock (s_sync) { if (s_singleton == null) { s_singleton = new SingletonLock(); } } } return(s_singleton); }
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(attribute, TestLockId, cancellationToken)).ReturnsAsync(lockOwner); SingletonLock singletonLock = new SingletonLock(TestLockId, TestInstanceId, attribute, mockSingletonManager.Object); await singletonLock.GetOwnerAsync(cancellationToken); }
public async Task SingletonWatcher_GetStatus_ReturnsExpectedValue() { Mock <SingletonManager> mockSingletonManager = new Mock <SingletonManager>(MockBehavior.Strict, null, null, null, null, null, new FixedHostIdProvider(TestHostId), null); mockSingletonManager.Setup(p => p.GetLockOwnerAsync(_attribute, _lockId, CancellationToken.None)).ReturnsAsync("someotherguy"); SingletonValueProvider localValueProvider = new SingletonValueProvider(_method, _attribute.ScopeId, TestInstanceId, _attribute, mockSingletonManager.Object); SingletonLock localSingletonLock = (SingletonLock)(await localValueProvider.GetValueAsync()); // set start time before _minimumWaitForFirstOwnerCheck in SingletonValueProvider DateTime startTime = DateTime.UtcNow - TimeSpan.FromSeconds(11); DateTime endTime = DateTime.UtcNow + TimeSpan.FromSeconds(2); DateTime releaseTime = endTime + TimeSpan.FromSeconds(1); // before lock is called SingletonValueProvider.SingletonWatcher watcher = (SingletonValueProvider.SingletonWatcher)localValueProvider.Watcher; SingletonParameterLog log = (SingletonParameterLog)watcher.GetStatus(); Assert.Null(log.LockOwner); Assert.False(log.LockAcquired); Assert.Null(log.LockDuration); Assert.Null(log.TimeToAcquireLock); // in the process of locking localSingletonLock.AcquireStartTime = startTime; log = (SingletonParameterLog)watcher.GetStatus(); Assert.Equal("someotherguy", log.LockOwner); Assert.False(log.LockAcquired); Assert.Null(log.LockDuration); Assert.NotNull(log.TimeToAcquireLock); // lock acquired but not released localSingletonLock.AcquireEndTime = endTime; log = (SingletonParameterLog)watcher.GetStatus(); Assert.Null(log.LockOwner); Assert.True(log.LockAcquired); Assert.NotNull(log.LockDuration); Assert.Equal(endTime - startTime, log.TimeToAcquireLock); // lock released localSingletonLock.ReleaseTime = releaseTime; log = (SingletonParameterLog)watcher.GetStatus(); Assert.Null(log.LockOwner); Assert.True(log.LockAcquired); Assert.Equal(releaseTime - endTime, log.LockDuration); Assert.Equal(endTime - startTime, log.TimeToAcquireLock); }
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); }
private static bool TryGetSingletonLock(IReadOnlyDictionary <string, IValueProvider> parameters, out SingletonLock singleton) { IValueProvider singletonValueProvider = null; singleton = null; if (parameters.TryGetValue(SingletonValueProvider.SingletonParameterName, out singletonValueProvider)) { singleton = (SingletonLock)singletonValueProvider.GetValue(); return(true); } return(false); }
internal static async Task ExecuteWithWatchersAsync(IFunctionInstance instance, IReadOnlyDictionary <string, IValueProvider> parameters, TraceWriter traceWriter, CancellationTokenSource functionCancellationTokenSource) { IFunctionInvoker invoker = instance.Invoker; IReadOnlyList <string> parameterNames = invoker.ParameterNames; IDelayedException delayedBindingException; object[] invokeParameters = PrepareParameters(parameterNames, parameters, out delayedBindingException); if (delayedBindingException != null) { // This is done inside a watcher context so that each binding error is publish next to the binding in // the parameter status log. delayedBindingException.Throw(); } // if the function is a Singleton, aquire the lock SingletonLock singleton = null; if (TryGetSingletonLock(parameters, out singleton)) { await singleton.AcquireAsync(functionCancellationTokenSource.Token); } // Create a source specifically for timeouts using (CancellationTokenSource timeoutTokenSource = new CancellationTokenSource()) { MethodInfo method = instance.FunctionDescriptor.Method; TimeoutAttribute timeoutAttribute = TypeUtility.GetHierarchicalAttributeOrNull <TimeoutAttribute>(method); bool throwOnTimeout = timeoutAttribute == null ? false : timeoutAttribute.ThrowOnTimeout; var timer = StartFunctionTimeout(instance, timeoutAttribute, timeoutTokenSource, traceWriter); TimeSpan timerInterval = timer == null ? TimeSpan.MinValue : TimeSpan.FromMilliseconds(timer.Interval); try { await InvokeAsync(invoker, invokeParameters, timeoutTokenSource, functionCancellationTokenSource, throwOnTimeout, timerInterval, instance); } finally { if (timer != null) { timer.Stop(); timer.Dispose(); } } } // Process any out parameters and persist any pending values. // Ensure IValueBinder.SetValue is called in BindStepOrder. This ordering is particularly important for // ensuring queue outputs occur last. That way, all other function side-effects are guaranteed to have // occurred by the time messages are enqueued. string[] parameterNamesInBindOrder = SortParameterNamesInStepOrder(parameters); foreach (string name in parameterNamesInBindOrder) { IValueProvider provider = parameters[name]; IValueBinder binder = provider as IValueBinder; if (binder != null) { object argument = invokeParameters[GetParameterIndex(parameterNames, name)]; try { // This could do complex things that may fail. Catch the exception. await binder.SetValueAsync(argument, functionCancellationTokenSource.Token); } catch (OperationCanceledException) { throw; } catch (Exception exception) { string message = String.Format(CultureInfo.InvariantCulture, "Error while handling parameter {0} after function returned:", name); throw new InvalidOperationException(message, exception); } } } if (singleton != null) { await singleton.ReleaseAsync(functionCancellationTokenSource.Token); } }
private async Task <string> ExecuteWithLoggingAsync(IFunctionInstance instance, FunctionStartedMessage message, FunctionInstanceLogEntry fastItem, IDictionary <string, ParameterLog> parameterLogCollector, TraceLevel functionTraceLevel, CancellationToken cancellationToken) { IFunctionOutputDefinition outputDefinition = null; IFunctionOutput outputLog = null; ITaskSeriesTimer updateOutputLogTimer = null; TextWriter functionOutputTextWriter = null; Func <Task> initializeOutputAsync = async() => { outputDefinition = await _functionOutputLogger.CreateAsync(instance, cancellationToken); outputLog = outputDefinition.CreateOutput(); functionOutputTextWriter = outputLog.Output; updateOutputLogTimer = StartOutputTimer(outputLog.UpdateCommand, _exceptionHandler); }; if (functionTraceLevel >= TraceLevel.Info) { await initializeOutputAsync(); } try { // Create a linked token source that will allow us to signal function cancellation // (e.g. Based on TimeoutAttribute, etc.) CancellationTokenSource functionCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); using (functionCancellationTokenSource) { // We create a new composite trace writer that will also forward // output to the function output log (in addition to console, user TraceWriter, etc.). TraceWriter traceWriter = new CompositeTraceWriter(_trace, functionOutputTextWriter, functionTraceLevel); // Must bind before logging (bound invoke string is included in log message). FunctionBindingContext functionContext = new FunctionBindingContext(instance.Id, functionCancellationTokenSource.Token, traceWriter); var valueBindingContext = new ValueBindingContext(functionContext, cancellationToken); var parameters = await instance.BindingSource.BindAsync(valueBindingContext); Exception invocationException = null; ExceptionDispatchInfo exceptionInfo = null; string startedMessageId = null; using (ValueProviderDisposable.Create(parameters)) { if (functionTraceLevel >= TraceLevel.Info) { startedMessageId = await LogFunctionStartedAsync(message, outputDefinition, parameters, cancellationToken); } if (_fastLogger != null) { // Log started fastItem.Arguments = message.Arguments; await _fastLogger.AddAsync(fastItem); } try { await ExecuteWithLoggingAsync(instance, parameters, traceWriter, outputDefinition, parameterLogCollector, functionTraceLevel, functionCancellationTokenSource); } catch (Exception ex) { invocationException = ex; } } if (invocationException != null) { if (outputDefinition == null) { // In error cases, even if logging is disabled for this function, we want to force // log errors. So we must delay initialize logging here await initializeOutputAsync(); startedMessageId = await LogFunctionStartedAsync(message, outputDefinition, parameters, cancellationToken); } // In the event of cancellation or timeout, we use the original exception without additional logging. if (invocationException is OperationCanceledException || invocationException is FunctionTimeoutException) { exceptionInfo = ExceptionDispatchInfo.Capture(invocationException); } else { string errorMessage = string.Format("Exception while executing function: {0}", instance.FunctionDescriptor.ShortName); FunctionInvocationException fex = new FunctionInvocationException(errorMessage, instance.Id, instance.FunctionDescriptor.FullName, invocationException); traceWriter.Error(errorMessage, fex, TraceSource.Execution); exceptionInfo = ExceptionDispatchInfo.Capture(fex); } } if (exceptionInfo == null && updateOutputLogTimer != null) { await updateOutputLogTimer.StopAsync(cancellationToken); } // after all execution is complete, flush the TraceWriter traceWriter.Flush(); // We save the exception info above rather than throwing to ensure we always write // console output even if the function fails or was canceled. if (outputLog != null) { await outputLog.SaveAndCloseAsync(fastItem, cancellationToken); } if (exceptionInfo != null) { // release any held singleton lock immediately SingletonLock singleton = null; if (TryGetSingletonLock(parameters, out singleton) && singleton.IsHeld) { await singleton.ReleaseAsync(cancellationToken); } exceptionInfo.Throw(); } return(startedMessageId); } } finally { if (outputLog != null) { ((IDisposable)outputLog).Dispose(); } if (updateOutputLogTimer != null) { ((IDisposable)updateOutputLogTimer).Dispose(); } } }
private async Task <string> ExecuteWithLogMessageAsync(IFunctionInstance instance, FunctionStartedMessage message, IDictionary <string, ParameterLog> parameterLogCollector, CancellationToken cancellationToken) { string startedMessageId; // Create the console output writer IFunctionOutputDefinition outputDefinition = await _functionOutputLogger.CreateAsync(instance, cancellationToken); // Create a linked token source that will allow us to signal function cancellation // (e.g. Based on TimeoutAttribute, etc.) CancellationTokenSource functionCancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); using (IFunctionOutput outputLog = await outputDefinition.CreateOutputAsync(cancellationToken)) using (ITaskSeriesTimer updateOutputLogTimer = StartOutputTimer(outputLog.UpdateCommand, _backgroundExceptionDispatcher)) using (functionCancellationTokenSource) { // We create a new composite trace writer that will also forward // output to the function output log (in addition to console, user TraceWriter, etc.). TraceWriter traceWriter = new CompositeTraceWriter(_trace, outputLog.Output); FunctionBindingContext functionContext = new FunctionBindingContext(instance.Id, functionCancellationTokenSource.Token, traceWriter); // Must bind before logging (bound invoke string is included in log message). IReadOnlyDictionary <string, IValueProvider> parameters = await instance.BindingSource.BindAsync(new ValueBindingContext(functionContext, cancellationToken)); ExceptionDispatchInfo exceptionInfo; using (ValueProviderDisposable.Create(parameters)) { startedMessageId = await LogFunctionStartedAsync(message, outputDefinition, parameters, cancellationToken); try { await ExecuteWithOutputLogsAsync(instance, parameters, traceWriter, outputDefinition, parameterLogCollector, functionCancellationTokenSource); exceptionInfo = null; } catch (OperationCanceledException exception) { exceptionInfo = ExceptionDispatchInfo.Capture(exception); } catch (Exception exception) { string errorMessage = string.Format("Exception while executing function: {0}", instance.FunctionDescriptor.ShortName); FunctionInvocationException functionException = new FunctionInvocationException(errorMessage, instance.Id, instance.FunctionDescriptor.FullName, exception); traceWriter.Error(errorMessage, functionException, TraceSource.Execution); exceptionInfo = ExceptionDispatchInfo.Capture(functionException); } } if (exceptionInfo == null && updateOutputLogTimer != null) { await updateOutputLogTimer.StopAsync(cancellationToken); } // after all execution is complete, flush the TraceWriter traceWriter.Flush(); // We save the exception info rather than doing throw; above to ensure we always write console output, // even if the function fails or was canceled. await outputLog.SaveAndCloseAsync(cancellationToken); if (exceptionInfo != null) { // release any held singleton lock immediately SingletonLock singleton = null; if (TryGetSingletonLock(parameters, out singleton) && singleton.IsHeld) { await singleton.ReleaseAsync(cancellationToken); } exceptionInfo.Throw(); } return(startedMessageId); } }
internal static async Task ExecuteWithWatchersAsync(IFunctionInvoker invoker, IReadOnlyDictionary <string, IValueProvider> parameters, CancellationToken cancellationToken) { IReadOnlyList <string> parameterNames = invoker.ParameterNames; IDelayedException delayedBindingException; object[] invokeParameters = PrepareParameters(parameterNames, parameters, out delayedBindingException); if (delayedBindingException != null) { // This is done inside a watcher context so that each binding error is publish next to the binding in // the parameter status log. delayedBindingException.Throw(); } // if the function is a Singleton, aquire the lock SingletonLock singleton = null; if (TryGetSingletonLock(parameters, out singleton)) { await singleton.AcquireAsync(cancellationToken); } // Cancellation token is provide by invokeParameters (if the method binds to CancellationToken). await invoker.InvokeAsync(invokeParameters); // Process any out parameters and persist any pending values. // Ensure IValueBinder.SetValue is called in BindOrder. This ordering is particularly important for // ensuring queue outputs occur last. That way, all other function side-effects are guaranteed to have // occurred by the time messages are enqueued. string[] parameterNamesInBindOrder = SortParameterNamesInStepOrder(parameters); foreach (string name in parameterNamesInBindOrder) { IValueProvider provider = parameters[name]; IValueBinder binder = provider as IValueBinder; if (binder != null) { object argument = invokeParameters[GetParameterIndex(parameterNames, name)]; try { // This could do complex things that may fail. Catch the exception. await binder.SetValueAsync(argument, cancellationToken); } catch (OperationCanceledException) { throw; } catch (Exception exception) { string message = String.Format(CultureInfo.InvariantCulture, "Error while handling parameter {0} after function returned:", name); throw new InvalidOperationException(message, exception); } } } if (singleton != null) { await singleton.ReleaseAsync(cancellationToken); } }