public override async Task <string> RunAsync(TaskContext context, string rawInput)
        {
            string instanceId   = context.OrchestrationInstance.InstanceId;
            var    inputContext = new DurableActivityContext(this.config, instanceId, rawInput);

            // TODO: Wire up the parent ID to improve dashboard logging.
            Guid?parentId     = null;
            var  triggerInput = new TriggeredFunctionData {
                ParentId = parentId, TriggerValue = inputContext
            };

            this.config.TraceHelper.FunctionStarting(
                this.config.Options.HubName,
                this.activityName,
                instanceId,
                this.config.GetIntputOutputTrace(rawInput),
                functionType: FunctionType.Activity,
                isReplay: false,
                taskEventId: this.taskEventId);

            WrappedFunctionResult result = await FunctionExecutionHelper.ExecuteActivityFunction(
                this.executor,
                triggerInput,
                this.hostServiceLifetime.OnStopping);

            switch (result.ExecutionStatus)
            {
            case WrappedFunctionResult.FunctionResultStatus.Success:
                string serializedOutput = inputContext.GetSerializedOutput();
                this.config.TraceHelper.FunctionCompleted(
                    this.config.Options.HubName,
                    this.activityName,
                    instanceId,
                    this.config.GetIntputOutputTrace(serializedOutput),
                    continuedAsNew: false,
                    functionType: FunctionType.Activity,
                    isReplay: false,
                    taskEventId: this.taskEventId);

                return(serializedOutput);

            case WrappedFunctionResult.FunctionResultStatus.FunctionsRuntimeError:
                this.config.TraceHelper.FunctionAborted(
                    this.config.Options.HubName,
                    this.activityName,
                    instanceId,
                    $"An internal error occurred while attempting to execute this function. The execution will be aborted and retried. Details: {result.Exception}",
                    functionType: FunctionType.Activity);

                // This will abort the execution and cause the message to go back onto the queue for re-processing
                throw new SessionAbortedException(
                          $"An internal error occurred while attempting to execute '{this.activityName}'.", result.Exception);

            case WrappedFunctionResult.FunctionResultStatus.UserCodeError:
                // Flow the original activity function exception to the orchestration
                // without the outer FunctionInvocationException.
                Exception exceptionToReport = StripFunctionInvocationException(result.Exception);

                if (OutOfProcExceptionHelpers.TryGetExceptionWithFriendlyMessage(
                        exceptionToReport,
                        out Exception friendlyMessageException))
                {
                    exceptionToReport = friendlyMessageException;
                }

                this.config.TraceHelper.FunctionFailed(
                    this.config.Options.HubName,
                    this.activityName,
                    instanceId,
                    exceptionToReport?.ToString() ?? string.Empty,
                    functionType: FunctionType.Activity,
                    isReplay: false,
                    taskEventId: this.taskEventId);

                throw new TaskFailureException(
                          $"Activity function '{this.activityName}' failed: {exceptionToReport.Message}",
                          Utils.SerializeCause(exceptionToReport, this.config.ErrorDataConverter));

            default:
                throw new InvalidOperationException($"{nameof(TaskActivityShim.RunAsync)} does not handle the function execution status {result.ExecutionStatus}.");
            }
        }
Exemple #2
0
        // Responsible for invoking the function, handling the exception, set the output, and if
        // the function execution is out-of-process, handles the replay.
        private async Task InvokeUserCodeAndHandleResults(
            RegisteredFunctionInfo orchestratorInfo,
            OrchestrationContext innerContext)
        {
            try
            {
                Task invokeTask = this.FunctionInvocationCallback();
                if (invokeTask is Task <object> resultTask)
                {
                    // Orchestrator threads cannot perform async I/O, so block on such out-of-proc threads.
                    // Possible performance implications; may need revisiting.
                    object returnValue = orchestratorInfo.IsOutOfProc ? resultTask.Result : await resultTask;
                    if (returnValue != null)
                    {
                        if (orchestratorInfo.IsOutOfProc)
                        {
                            await this.TraceAndReplay(returnValue);
                        }
                        else
                        {
                            this.context.SetOutput(returnValue);
                        }
                    }
                }
                else
                {
                    throw new InvalidOperationException("The WebJobs runtime returned a invocation task that does not support return values!");
                }
            }
            catch (Exception e)
            {
                if (orchestratorInfo != null &&
                    orchestratorInfo.IsOutOfProc &&
                    OutOfProcExceptionHelpers.TryExtractOutOfProcStateJson(e.InnerException, out string returnValue) &&
                    !string.IsNullOrEmpty(returnValue))
                {
                    try
                    {
                        await this.TraceAndReplay(returnValue, e);
                    }
                    catch (OrchestrationFailureException ex)
                    {
                        this.TraceAndSendExceptionNotification(ex.Details);
                        this.context.OrchestrationException = ExceptionDispatchInfo.Capture(ex);
                        throw ex;
                    }
                }
                else
                {
                    this.TraceAndSendExceptionNotification(e.ToString());
                    var orchestrationException = new OrchestrationFailureException(
                        $"Orchestrator function '{this.context.Name}' failed: {e.Message}",
                        Utils.SerializeCause(e, innerContext.ErrorDataConverter));

                    this.context.OrchestrationException =
                        ExceptionDispatchInfo.Capture(orchestrationException);

#if !FUNCTIONS_V1
                    DurableTaskExtension.TagActivityWithOrchestrationStatus(OrchestrationRuntimeStatus.Failed, this.context.InstanceId);
#endif

                    throw orchestrationException;
                }
            }
            finally
            {
                this.context.IsCompleted = true;
            }
        }