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);
                }
        }
示例#2
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);
                    }
        }