Esempio n. 1
0
        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);
                }
            }
        }
Esempio n. 2
0
        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);
                }
            }
        }
        private async Task ExecuteWithOutputLogsAsync(IFunctionInstance instance,
                                                      IReadOnlyDictionary <string, IValueProvider> parameters,
                                                      TextWriter consoleOutput,
                                                      IFunctionOutputDefinition outputDefinition,
                                                      IDictionary <string, ParameterLog> parameterLogCollector,
                                                      CancellationToken cancellationToken)
        {
            IFunctionInvoker invoker = instance.Invoker;
            IReadOnlyDictionary <string, IWatcher> watches = CreateWatches(parameters);
            IRecurrentCommand updateParameterLogCommand    =
                outputDefinition.CreateParameterLogUpdateCommand(watches, consoleOutput);

            using (ITaskSeriesTimer updateParameterLogTimer = StartParameterLogTimer(updateParameterLogCommand,
                                                                                     _backgroundExceptionDispatcher))
            {
                try
                {
                    await ExecuteWithWatchersAsync(invoker, parameters, cancellationToken);

                    if (updateParameterLogTimer != null)
                    {
                        // Stop the watches after calling IValueBinder.SetValue (it may do things that should show up in
                        // the watches).
                        // Also, IValueBinder.SetValue could also take a long time (flushing large caches), and so it's
                        // useful to have watches still running.
                        await updateParameterLogTimer.StopAsync(cancellationToken);
                    }
                }
                finally
                {
                    ValueWatcher.AddLogs(watches, parameterLogCollector);
                }
            }
        }
        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));
            }
        }
Esempio n. 5
0
        public void Cancel_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

                        // Act
                        product.Cancel();

                        // Assert
                        Assert.True(executeFinished.WaitOne(1000)); // Guard
                        Assert.True(cancellationTokenSignalled);

                        // Cleanup
                        product.StopAsync(CancellationToken.None).GetAwaiter().GetResult();
                    }
                }
        }
Esempio n. 6
0
        public async Task StopAsync(CancellationToken cancellationToken)
        {
            ThrowIfDisposed();
            _timer.Cancel();
            await Task.WhenAll(_processing);

            await _timer.StopAsync(cancellationToken);
        }
Esempio n. 7
0
        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.");
            }
        }
Esempio n. 8
0
        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));
            }
        }
Esempio n. 9
0
        public async Task EnsureAllStoppedAsync(CancellationToken cancellationToken)
        {
            if (_started)
            {
                _strategy.Cancel();
                await _timer.StopAsync(cancellationToken);

                _started = false;
            }
        }
Esempio n. 10
0
        public async Task StopAsync(CancellationToken cancellationToken)
        {
            using (cancellationToken.Register(() => _shutdownCancellationTokenSource.Cancel()))
            {
                ThrowIfDisposed();
                _timer.Cancel();
                await Task.WhenAll(_processing).ConfigureAwait(false);

                await _timer.StopAsync(cancellationToken).ConfigureAwait(false);
            }
        }
Esempio n. 11
0
        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());
        }
Esempio n. 12
0
        public void StopAsync_IfDisposed_Throws()
        {
            // Arrange
            ITaskSeriesCommand command = CreateDummyCommand();
            ITaskSeriesTimer   product = CreateProductUnderTest(command);

            product.Dispose();

            CancellationToken cancellationToken = CancellationToken.None;

            // Act & Assert
            ExceptionAssert.ThrowsObjectDisposed(() => product.StopAsync(cancellationToken));
        }
Esempio n. 13
0
        public void StopAsync_IfNotStarted_Throws()
        {
            // Arrange
            ITaskSeriesCommand command = CreateDummyCommand();

            using (ITaskSeriesTimer product = CreateProductUnderTest(command))
            {
                CancellationToken cancellationToken = CancellationToken.None;

                // Act & Assert
                ExceptionAssert.ThrowsInvalidOperation(() => product.StopAsync(cancellationToken),
                                                       "The timer has not yet been started.");
            }
        }
        private async Task ExecuteWithLoggingAsync(IFunctionInstance instance,
                                                   IReadOnlyDictionary <string, IValueProvider> parameters,
                                                   TraceWriter trace,
                                                   ILogger logger,
                                                   IFunctionOutputDefinition outputDefinition,
                                                   IDictionary <string, ParameterLog> parameterLogCollector,
                                                   TraceLevel functionTraceLevel,
                                                   CancellationTokenSource functionCancellationTokenSource)
        {
            IFunctionInvoker invoker = instance.Invoker;

            IReadOnlyDictionary <string, IWatcher> parameterWatchers = null;
            ITaskSeriesTimer updateParameterLogTimer = null;

            if (functionTraceLevel >= TraceLevel.Info)
            {
                parameterWatchers = CreateParameterWatchers(parameters);
                IRecurrentCommand updateParameterLogCommand = outputDefinition.CreateParameterLogUpdateCommand(parameterWatchers, trace, logger);
                updateParameterLogTimer = StartParameterLogTimer(updateParameterLogCommand, _exceptionHandler);
            }

            try
            {
                await ExecuteWithWatchersAsync(instance, parameters, trace, logger, functionCancellationTokenSource);

                if (updateParameterLogTimer != null)
                {
                    // Stop the watches after calling IValueBinder.SetValue (it may do things that should show up in
                    // the watches).
                    // Also, IValueBinder.SetValue could also take a long time (flushing large caches), and so it's
                    // useful to have watches still running.
                    await updateParameterLogTimer.StopAsync(functionCancellationTokenSource.Token);
                }
            }
            finally
            {
                if (updateParameterLogTimer != null)
                {
                    ((IDisposable)updateParameterLogTimer).Dispose();
                }

                if (parameterWatchers != null)
                {
                    ValueWatcher.AddLogs(parameterWatchers, parameterLogCollector);
                }
            }
        }
Esempio n. 15
0
        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);
        }
Esempio n. 16
0
        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.
            }
        }
Esempio n. 17
0
        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);
                    }
                }
        }
Esempio n. 18
0
        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);
                }
            }
        }
Esempio n. 19
0
        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();
                    }
                }
        }
Esempio n. 20
0
        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);
            }
        }
Esempio n. 21
0
        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);
                    }
        }
        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();
                }
            }
        }
Esempio n. 23
0
 public Task StopAsync(CancellationToken cancellationToken)
 {
     ThrowIfDisposed();
     return(_timer.StopAsync(cancellationToken));
 }
Esempio n. 24
0
        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);

            using (IFunctionOutput outputLog = await outputDefinition.CreateOutputAsync(cancellationToken))
                using (ITaskSeriesTimer updateOutputLogTimer = StartOutputTimer(outputLog.UpdateCommand, _backgroundExceptionDispatcher))
                {
                    TextWriter             consoleOutput   = outputLog.Output;
                    FunctionBindingContext functionContext = new FunctionBindingContext(instance.Id, cancellationToken, consoleOutput);

                    // 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, consoleOutput, outputDefinition,
                                                             parameterLogCollector, cancellationToken);

                            exceptionInfo = null;
                        }
                        catch (OperationCanceledException exception)
                        {
                            exceptionInfo = ExceptionDispatchInfo.Capture(exception);
                        }
                        catch (Exception exception)
                        {
                            consoleOutput.WriteLine("--------");
                            consoleOutput.WriteLine("Exception while executing:");
                            consoleOutput.Write(exception.ToDetails());
                            exceptionInfo = ExceptionDispatchInfo.Capture(exception);
                        }
                    }

                    if (exceptionInfo == null && updateOutputLogTimer != null)
                    {
                        await updateOutputLogTimer.StopAsync(cancellationToken);
                    }

                    // 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)
                    {
                        exceptionInfo.Throw();
                    }

                    return(startedMessageId);
                }
        }
        public async Task StopAsync(CancellationToken cancellationToken)
        {
            await _timer.StopAsync(cancellationToken);

            await _innerListener.StopAsync(cancellationToken);
        }