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}."); } }
// 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; } }