public void Start_IfStarted_Throws() { // Arrange ITaskSeriesCommand command = CreateStubCommand(TimeSpan.FromDays(1)); using (ITaskSeriesTimer product = CreateProductUnderTest(command)) { product.Start(); // Act & Assert ExceptionAssert.ThrowsInvalidOperation(() => product.Start(), "The timer has already been started; it cannot be restarted."); } }
public void StopAsync_TriggersCommandCancellationToken() { // Arrange using (EventWaitHandle executeStarted = new ManualResetEvent(initialState: false)) using (EventWaitHandle executeFinished = new ManualResetEvent(initialState: false)) { bool cancellationTokenSignalled = false; ITaskSeriesCommand command = CreateCommand((cancellationToken) => { Assert.True(executeStarted.Set()); // Guard cancellationTokenSignalled = cancellationToken.WaitHandle.WaitOne(1000); Assert.True(executeFinished.Set()); // Guard return(new TaskSeriesCommandResult(wait: Task.Delay(0))); }); using (ITaskSeriesTimer product = CreateProductUnderTest(command)) { product.Start(); Assert.True(executeStarted.WaitOne(1000)); // Guard CancellationToken cancellationToken = CancellationToken.None; // Act Task task = product.StopAsync(cancellationToken); // Assert Assert.NotNull(task); task.GetAwaiter().GetResult(); Assert.True(executeFinished.WaitOne(1000)); // Guard Assert.True(cancellationTokenSignalled); } } }
public void StopAsync_DoesNotWaitForSubsequentWaitToCompleteTask() { // Arrange using (EventWaitHandle executeStarted = new ManualResetEvent(initialState: false)) { ITaskSeriesCommand command = CreateCommand(() => { Assert.True(executeStarted.Set()); // Guard return(new TaskSeriesCommandResult(wait: Task.Delay(2000))); }); using (ITaskSeriesTimer product = CreateProductUnderTest(command)) { product.Start(); Assert.True(executeStarted.WaitOne(1000)); // Guard // Wait for the background thread to enter the long wait. Thread.Sleep(5); CancellationToken cancellationToken = CancellationToken.None; // Act Task task = product.StopAsync(cancellationToken); // Assert Assert.NotNull(task); Assert.True(task.WaitUntilCompleted(1000)); Assert.True(task.IsCompleted); } } }
public void Start_AfterInitialWait_Executes() { // Arrange // Detect the difference between waiting and not waiting, but keep the test execution time fast. TimeSpan initialDelay = TimeSpan.FromMilliseconds(50); using (EventWaitHandle executedWaitHandle = new ManualResetEvent(initialState: false)) { ITaskSeriesCommand command = CreateCommand(() => { Assert.True(executedWaitHandle.Set()); // Guard return(new TaskSeriesCommandResult(wait: Task.Delay(TimeSpan.FromDays(1)))); }); using (ITaskSeriesTimer product = CreateProductUnderTest(command, Task.Delay(initialDelay))) { Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); // Act product.Start(); // Assert Assert.True(executedWaitHandle.WaitOne(1000)); // Guard stopwatch.Stop(); // Account for the resolution of the system timer; otherwise, the test may fail intermittently // (as the timer may fire slightly before the precise expected value). TimeSpan effectiveActualDelay = AddSystemTimerResolution(stopwatch.Elapsed); AssertGreaterThan(initialDelay, effectiveActualDelay); } } }
internal async Task ProcessMessageAsync(IStorageQueueMessage message, TimeSpan visibilityTimeout, CancellationToken cancellationToken) { try { if (!await _queueProcessor.BeginProcessingMessageAsync(message.SdkObject, cancellationToken)) { return; } FunctionResult result = null; using (ITaskSeriesTimer timer = CreateUpdateMessageVisibilityTimer(_queue, message, visibilityTimeout, _backgroundExceptionDispatcher)) { timer.Start(); result = await _triggerExecutor.ExecuteAsync(message, cancellationToken); await timer.StopAsync(cancellationToken); } await _queueProcessor.CompleteProcessingMessageAsync(message.SdkObject, result, cancellationToken); } catch (OperationCanceledException) { // Don't fail the top-level task when an inner task cancels. } catch (Exception exception) { // Immediately report any unhandled exception from this background task. // (Don't capture the exception as a fault of this Task; that would delay any exception reporting until // Stop is called, which might never happen.) _backgroundExceptionDispatcher.Throw(ExceptionDispatchInfo.Capture(exception)); } }
public void Dispose_TriggersCommandCancellationToken() { // Arrange TimeSpan interval = TimeSpan.Zero; using (EventWaitHandle executeStarted = new ManualResetEvent(initialState: false)) using (EventWaitHandle executeFinished = new ManualResetEvent(initialState: false)) { bool cancellationTokenSignalled = false; ITaskSeriesCommand command = CreateCommand((cancellationToken) => { Assert.True(executeStarted.Set()); // Guard cancellationTokenSignalled = cancellationToken.WaitHandle.WaitOne(1000); Assert.True(executeFinished.Set()); // Guard return(new TaskSeriesCommandResult(wait: Task.Delay(0))); }); using (ITaskSeriesTimer product = CreateProductUnderTest(command)) { product.Start(); Assert.True(executeStarted.WaitOne(1000)); // Guard // Act product.Dispose(); // Assert Assert.True(executeFinished.WaitOne(1000)); // Guard Assert.True(cancellationTokenSignalled); } } }
public void Dispose_IfStarted_DoesNotWaitForExecuteToFinish() { // Arrange using (EventWaitHandle executeStarted = new ManualResetEvent(initialState: false)) using (EventWaitHandle stopExecute = new ManualResetEvent(initialState: false)) { bool waitedForCommandToFinish = false; ITaskSeriesCommand command = CreateCommand(() => { Assert.True(executeStarted.Set()); // Guard stopExecute.WaitOne(1000); waitedForCommandToFinish = true; return(new TaskSeriesCommandResult(wait: Task.Delay(0))); }); using (ITaskSeriesTimer product = CreateProductUnderTest(command)) { product.Start(); Assert.True(executeStarted.WaitOne(1000)); // Guard // Act & Assert product.Dispose(); // Assert Assert.False(waitedForCommandToFinish); // Cleanup Assert.True(stopExecute.Set()); // Guard } } }
public void StopAsync_WhenCanceled_DoesNotWaitForExecuteToFinishToCompleteTask() { // Arrange using (EventWaitHandle executeStarted = new ManualResetEvent(initialState: false)) { ITaskSeriesCommand command = CreateCommand(() => { Assert.True(executeStarted.Set()); // Guard return(new TaskSeriesCommandResult(wait: Task.Delay(2000))); }); using (ITaskSeriesTimer product = CreateProductUnderTest(command)) { product.Start(); Assert.True(executeStarted.WaitOne(1000)); // Guard CancellationToken cancellationToken = new CancellationToken(canceled: true); // Act Task task = product.StopAsync(cancellationToken); // Assert Assert.NotNull(task); Assert.True(task.WaitUntilCompleted(1000)); Assert.True(task.IsCompleted); } } }
public async Task StartAsync(CancellationToken cancellationToken) { await _innerListener.StartAsync(cancellationToken); await _heartbeatCommand.TryExecuteAsync(cancellationToken); _timer.Start(); }
// Begin watchers. public ValueWatcher(IReadOnlyDictionary<string, IWatcher> watches, CloudBlockBlob blobResults, TextWriter consoleOutput, IBackgroundExceptionDispatcher backgroundExceptionDispatcher) { ValueWatcherCommand command = new ValueWatcherCommand(watches, blobResults, consoleOutput); _command = command; _timer = ValueWatcherCommand.CreateTimer(command, backgroundExceptionDispatcher); _timer.Start(); }
// Begin watchers. public ValueWatcher(IReadOnlyDictionary <string, IWatcher> watches, CloudBlockBlob blobResults, TextWriter consoleOutput, IBackgroundExceptionDispatcher backgroundExceptionDispatcher) { ValueWatcherCommand command = new ValueWatcherCommand(watches, blobResults, consoleOutput); _command = command; _timer = ValueWatcherCommand.CreateTimer(command, backgroundExceptionDispatcher); _timer.Start(); }
public static RenewableLockHandle CreateRenewableLockHandle(TimeSpan leasePeriod, IDistributedLockManager distributedLockManager, IDistributedLock lockHandle, Func <bool> preExecuteCheck) { ITaskSeriesTimer renewal = CreateLeaseRenewalTimer(leasePeriod, distributedLockManager, lockHandle, preExecuteCheck); renewal.Start(); return(new RenewableLockHandle(lockHandle, renewal)); }
private async Task ProcessMessageAsync(IStorageQueueMessage message, TimeSpan visibilityTimeout, CancellationToken cancellationToken) { try { bool succeeded; using (ITaskSeriesTimer timer = CreateUpdateMessageVisibilityTimer(_queue, message, visibilityTimeout, _backgroundExceptionDispatcher)) { timer.Start(); succeeded = await _triggerExecutor.ExecuteAsync(message, cancellationToken); await timer.StopAsync(cancellationToken); } // Need to call Delete message only if function succeeded. if (succeeded) { await DeleteMessageAsync(message, cancellationToken); } else if (_poisonQueue != null) { if (message.DequeueCount >= _maxDequeueCount) { _log.WriteLine("Message has reached MaxDequeueCount of {0}. Moving message to queue '{1}'.", _maxDequeueCount, _poisonQueue.Name); await CopyToPoisonQueueAsync(message, cancellationToken); await DeleteMessageAsync(message, cancellationToken); } else { await ReleaseMessageAsync(message, cancellationToken); } } else { // For queues without a corresponding poison queue, leave the message invisible when processing // fails to prevent a fast infinite loop. // Specifically, don't call ReleaseMessage(message) } } catch (OperationCanceledException) { // Don't fail the top-level task when an inner task cancels. } catch (Exception exception) { // Immediately report any unhandled exception from this background task. // (Don't capture the exception as a fault of this Task; that would delay any exception reporting until // Stop is called, which might never happen.) _backgroundExceptionDispatcher.Throw(ExceptionDispatchInfo.Capture(exception)); } }
public Task EnsureAllStartedAsync(CancellationToken cancellationToken) { if (!_started) { _timer.Start(); _strategy.Start(); _started = true; } return(Task.FromResult(0)); }
public void Start_IfDisposed_Throws() { // Arrange ITaskSeriesCommand command = CreateDummyCommand(); ITaskSeriesTimer product = CreateProductUnderTest(command); product.Dispose(); // Act & Assert ExceptionAssert.ThrowsObjectDisposed(() => product.Start()); }
public void Dispose_IfStopped_DoesNotThrow() { // Arrange ITaskSeriesCommand command = CreateStubCommand(TimeSpan.Zero); ITaskSeriesTimer product = CreateProductUnderTest(command); product.Start(); product.StopAsync(CancellationToken.None).GetAwaiter().GetResult(); // Act & Assert ExceptionAssert.DoesNotThrow(() => product.Dispose()); }
private static ITaskSeriesTimer StartParameterLogTimer(IRecurrentCommand updateCommand, IWebJobsExceptionHandler exceptionHandler) { if (updateCommand == null) { return(null); } TimeSpan initialDelay = FunctionParameterLogIntervals.InitialDelay; TimeSpan refreshRate = FunctionParameterLogIntervals.RefreshRate; ITaskSeriesTimer timer = FixedDelayStrategy.CreateTimer(updateCommand, initialDelay, refreshRate, exceptionHandler); timer.Start(); return(timer); }
private static ITaskSeriesTimer StartOutputTimer(IRecurrentCommand updateCommand, IBackgroundExceptionDispatcher backgroundExceptionDispatcher) { if (updateCommand == null) { return(null); } TimeSpan initialDelay = FunctionOutputIntervals.InitialDelay; TimeSpan refreshRate = FunctionOutputIntervals.RefreshRate; ITaskSeriesTimer timer = FixedDelayStrategy.CreateTimer(updateCommand, initialDelay, refreshRate, backgroundExceptionDispatcher); timer.Start(); return(timer); }
public async Task <IDelayedException> TryExecuteAsync(IFunctionInstance instance, CancellationToken cancellationToken) { IDelayedException result; using (ITaskSeriesTimer timer = CreateHeartbeatTimer(_exceptionHandler)) { await _heartbeatCommand.TryExecuteAsync(cancellationToken); timer.Start(); result = await _innerExecutor.TryExecuteAsync(instance, cancellationToken); await timer.StopAsync(cancellationToken); } return(result); }
public void StopAsync_IfAlreadyStopped_Throws() { // Arrange ITaskSeriesCommand command = CreateStubCommand(TimeSpan.Zero); using (ITaskSeriesTimer product = CreateProductUnderTest(command)) { product.Start(); product.StopAsync(CancellationToken.None).GetAwaiter().GetResult(); CancellationToken cancellationToken = CancellationToken.None; // Act & Assert ExceptionAssert.ThrowsInvalidOperation(() => product.StopAsync(cancellationToken), "The timer has already been stopped."); } }
public void Start_AfterExecute_WaitsForReturnedWait() { // Arrange bool executedOnce = false; bool executedTwice = false; TimeSpan initialInterval = TimeSpan.Zero; // Detect the difference between waiting and not waiting, but keep the test execution time fast. TimeSpan subsequentInterval = TimeSpan.FromMilliseconds(5); Stopwatch stopwatch = new Stopwatch(); using (EventWaitHandle waitForSecondExecution = new ManualResetEvent(initialState: false)) { ITaskSeriesCommand command = CreateCommand(() => { if (executedTwice) { return(new TaskSeriesCommandResult(wait: Task.Delay(TimeSpan.FromDays(1)))); } if (!executedOnce) { stopwatch.Start(); executedOnce = true; return(new TaskSeriesCommandResult(wait: Task.Delay(subsequentInterval))); } else { stopwatch.Stop(); executedTwice = true; Assert.True(waitForSecondExecution.Set()); // Guard return(new TaskSeriesCommandResult(wait: Task.Delay(initialInterval))); } }); using (ITaskSeriesTimer product = CreateProductUnderTest(command)) { // Act product.Start(); // Assert Assert.True(waitForSecondExecution.WaitOne(1000)); // Guard AssertGreaterThan(subsequentInterval, stopwatch.Elapsed); } } }
internal async Task ProcessMessageAsync(QueueMessage message, TimeSpan visibilityTimeout, CancellationToken cancellationToken) { try { if (!await _queueProcessor.BeginProcessingMessageAsync(message, cancellationToken).ConfigureAwait(false)) { return; } FunctionResult result = null; Action <UpdateReceipt> onUpdateReceipt = updateReceipt => { message = message.Update(updateReceipt); }; using (ITaskSeriesTimer timer = CreateUpdateMessageVisibilityTimer(_queue, message, visibilityTimeout, _exceptionHandler, onUpdateReceipt)) { timer.Start(); result = await _triggerExecutor.ExecuteAsync(message, cancellationToken).ConfigureAwait(false); await timer.StopAsync(cancellationToken).ConfigureAwait(false); } // Use a different cancellation token for shutdown to allow graceful shutdown. // Specifically, don't cancel the completion or update of the message itself during graceful shutdown. // Only cancel completion or update of the message if a non-graceful shutdown is requested via _shutdownCancellationTokenSource. await _queueProcessor.CompleteProcessingMessageAsync(message, result, _shutdownCancellationTokenSource.Token).ConfigureAwait(false); } catch (TaskCanceledException) { // Don't fail the top-level task when an inner task cancels. } catch (OperationCanceledException) { // Don't fail the top-level task when an inner task cancels. } catch (Exception exception) { // Immediately report any unhandled exception from this background task. // (Don't capture the exception as a fault of this Task; that would delay any exception reporting until // Stop is called, which might never happen.) #pragma warning disable AZC0103 // Do not wait synchronously in asynchronous scope. _exceptionHandler.OnUnhandledExceptionAsync(ExceptionDispatchInfo.Capture(exception)).GetAwaiter().GetResult(); #pragma warning restore AZC0103 // Do not wait synchronously in asynchronous scope. } }
public void StopAsync_WaitsForTaskCompletionToCompleteTask() { // Arrange bool executedOnce = false; bool taskCompleted = false; using (EventWaitHandle executeStarted = new ManualResetEvent(initialState: false)) using (EventWaitHandle stopExecuteInFiveMilliseconds = new ManualResetEvent(initialState: false)) { ITaskSeriesCommand command = CreateCommand(async() => { if (executedOnce) { return(new TaskSeriesCommandResult(wait: Task.Delay(0))); } executedOnce = true; Assert.True(executeStarted.Set()); // Guard // Detect the difference between waiting and not waiting, but keep the test execution time fast. await Task.Delay(5); taskCompleted = true; return(new TaskSeriesCommandResult(wait: Task.Delay(0))); }); using (ITaskSeriesTimer product = CreateProductUnderTest(command)) { product.Start(); Assert.True(executeStarted.WaitOne(1000)); // Guard Assert.True(stopExecuteInFiveMilliseconds.Set()); // Guard CancellationToken cancellationToken = CancellationToken.None; // Act Task stopTask = product.StopAsync(cancellationToken); // Assert Assert.NotNull(stopTask); stopTask.GetAwaiter().GetResult(); Assert.True(taskCompleted); } } }
public void Start_IfCommandExecuteAsyncsReturnsCanceledTask_DoesNotCallBackgroundExceptionDispatcher() { // Arrange bool executedOnce = false; using (EventWaitHandle executedTwiceWaitHandle = new ManualResetEvent(initialState: false)) { ITaskSeriesCommand command = CreateCommand(() => { if (executedOnce) { Assert.True(executedTwiceWaitHandle.Set()); // Guard return(Task.FromResult(new TaskSeriesCommandResult(Task.Delay(TimeSpan.FromDays(1))))); } executedOnce = true; TaskCompletionSource <TaskSeriesCommandResult> taskSource = new TaskCompletionSource <TaskSeriesCommandResult>(); taskSource.SetCanceled(); return(taskSource.Task); }); Mock <IWebJobsExceptionHandler> exceptionHandlerMock = new Mock <IWebJobsExceptionHandler>(MockBehavior.Strict); int backgroundExceptionCalls = 0; exceptionHandlerMock .Setup(d => d.OnUnhandledExceptionAsync(It.IsAny <ExceptionDispatchInfo>())) .Callback(() => backgroundExceptionCalls++); IWebJobsExceptionHandler exceptionHandler = exceptionHandlerMock.Object; using (ITaskSeriesTimer product = CreateProductUnderTest(command, exceptionHandler)) { // Act product.Start(); // Assert Assert.True(executedTwiceWaitHandle.WaitOne(1000)); // Guard Assert.Equal(0, backgroundExceptionCalls); } } }
public void StopAsync_WhenExecuteTaskCompletesFaulted_DoesNotThrowOrFault() { // Arrange bool executedOnce = false; using (EventWaitHandle executeStarted = new ManualResetEvent(initialState: false)) using (EventWaitHandle stopExecuteInFiveMilliseconds = new ManualResetEvent(initialState: false)) { ITaskSeriesCommand command = CreateCommand(() => { if (executedOnce) { return(Task.FromResult(new TaskSeriesCommandResult(wait: Task.Delay(0)))); } executedOnce = true; Assert.True(executeStarted.Set()); // Guard TaskCompletionSource <TaskSeriesCommandResult> taskSource = new TaskCompletionSource <TaskSeriesCommandResult>(); taskSource.SetException(new InvalidOperationException()); return(taskSource.Task); }); IWebJobsExceptionHandler ignoreDispatcher = CreateIgnoreBackgroundExceptionDispatcher(); using (ITaskSeriesTimer product = CreateProductUnderTest(command, ignoreDispatcher)) { product.Start(); Assert.True(executeStarted.WaitOne(1000)); // Guard CancellationToken cancellationToken = CancellationToken.None; // Act Task task = product.StopAsync(cancellationToken); // Assert Assert.NotNull(task); task.GetAwaiter().GetResult(); } } }
public void StopAsync_TriggersNotExecutingAgain() { // Arrange using (EventWaitHandle executedOnceWaitHandle = new ManualResetEvent(initialState: false)) { ITaskSeriesTimer product = null; Task stop = null; bool executedOnce = false; bool executedTwice = false; ITaskSeriesCommand command = CreateCommand(() => { if (!executedOnce) { stop = product.StopAsync(CancellationToken.None); Assert.True(executedOnceWaitHandle.Set()); // Guard executedOnce = true; return(new TaskSeriesCommandResult(wait: Task.Delay(0))); } else { executedTwice = true; return(new TaskSeriesCommandResult(wait: Task.Delay(0))); } }); using (product = CreateProductUnderTest(command)) { product.Start(); // Act bool executed = executedOnceWaitHandle.WaitOne(1000); // Assert Assert.True(executed); // Guard Assert.NotNull(stop); stop.GetAwaiter().GetResult(); Assert.False(executedTwice); } } }
public void Start_IfCommandExecuteAsyncsReturnsFaultedTask_CallsBackgroundExceptionDispatcher() { // Arrange Exception expectedException = new Exception(); ITaskSeriesCommand command = CreateCommand(() => { TaskCompletionSource <TaskSeriesCommandResult> taskSource = new TaskCompletionSource <TaskSeriesCommandResult>(); taskSource.SetException(expectedException); return(taskSource.Task); }); using (EventWaitHandle exceptionDispatchedWaitHandle = new ManualResetEvent(initialState: false)) { Mock <IWebJobsExceptionHandler> exceptionHandlerMock = new Mock <IWebJobsExceptionHandler>(MockBehavior.Strict); ExceptionDispatchInfo exceptionInfo = null; exceptionHandlerMock .Setup(d => d.OnUnhandledExceptionAsync(It.IsAny <ExceptionDispatchInfo>())) .Callback <ExceptionDispatchInfo>((i) => { exceptionInfo = i; Assert.True(exceptionDispatchedWaitHandle.Set()); // Guard }); IWebJobsExceptionHandler exceptionHandler = exceptionHandlerMock.Object; using (ITaskSeriesTimer product = CreateProductUnderTest(command, exceptionHandler)) { // Act product.Start(); // Assert Assert.True(exceptionDispatchedWaitHandle.WaitOne(1000)); // Guard Assert.NotNull(exceptionInfo); Assert.Same(expectedException, exceptionInfo.SourceException); } } }
public void StopAsync_DoesNotWaitForInitialWaitToCompleteTask() { // Arrange ITaskSeriesCommand command = CreateStubCommand(TimeSpan.Zero); using (ITaskSeriesTimer product = CreateProductUnderTest(command, initialWait: Task.Delay(2000))) { product.Start(); // Wait for the background thread to enter the initialWait. Thread.Sleep(5); CancellationToken cancellationToken = CancellationToken.None; // Act Task task = product.StopAsync(cancellationToken); // Assert Assert.NotNull(task); Assert.True(task.WaitUntilCompleted(1000)); Assert.True(task.IsCompleted); } }
public void Start_IfCommandExecuteAsyncsThrows_CallsBackgroundExceptionDispatcher() { // Arrange Exception expectedException = new Exception(); TimeSpan interval = TimeSpan.Zero; using (EventWaitHandle exceptionDispatchedWaitHandle = new ManualResetEvent(initialState: false)) { Func <Task <TaskSeriesCommandResult> > execute = () => { throw expectedException; }; ITaskSeriesCommand command = CreateCommand(execute); Mock <IWebJobsExceptionHandler> exceptionHandlerMock = new Mock <IWebJobsExceptionHandler>(MockBehavior.Strict); ExceptionDispatchInfo exceptionInfo = null; exceptionHandlerMock .Setup(d => d.OnUnhandledExceptionAsync(It.IsAny <ExceptionDispatchInfo>())) .Callback <ExceptionDispatchInfo>((i) => { exceptionInfo = i; Assert.True(exceptionDispatchedWaitHandle.Set()); // Guard }); IWebJobsExceptionHandler exceptionHandler = exceptionHandlerMock.Object; using (ITaskSeriesTimer product = CreateProductUnderTest(command, exceptionHandler)) { // Act product.Start(); // Assert bool executed = exceptionDispatchedWaitHandle.WaitOne(1000); Assert.True(executed); Assert.NotNull(exceptionInfo); Assert.Same(expectedException, exceptionInfo.SourceException); } } }
public Task StartAsync(CancellationToken cancellationToken) { ThrowIfDisposed(); _timer.Start(); return(Task.FromResult(0)); }