public Task <ITriggerData> BindAsync(object value, ValueBindingContext context)
            {
                IConverterManager cm = this.parent.extensionContext.Config.ConverterManager;
                MethodInfo        getConverterMethod = cm.GetType().GetMethod(nameof(cm.GetConverter));

                getConverterMethod = getConverterMethod.MakeGenericMethod(
                    typeof(DurableActivityContext),
                    this.parameterInfo.ParameterType,
                    typeof(ActivityTriggerAttribute));

                Delegate d = (Delegate)getConverterMethod.Invoke(cm, null);
                object   convertedValue = d.DynamicInvoke(value, this.attribute, context);

                var valueProvider = new ObjectValueProvider(
                    convertedValue,
                    this.parameterInfo.ParameterType);

                DurableActivityContext activityContext = (DurableActivityContext)value;
                var bindingData = new Dictionary <string, object>(StringComparer.OrdinalIgnoreCase)
                {
                    { nameof(DurableActivityContext.InstanceId), activityContext.InstanceId }
                };

                var triggerData = new TriggerData(valueProvider, bindingData);

                return(Task.FromResult <ITriggerData>(triggerData));
            }
        public override async Task <string> RunAsync(TaskContext context, string rawInput)
        {
            string instanceId   = context.OrchestrationInstance.InstanceId;
            var    inputContext = new DurableActivityContext(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.HubName,
                this.activityName,
                this.activityVersion,
                instanceId,
                this.config.GetIntputOutputTrace(rawInput),
                functionType: FunctionType.Activity,
                isReplay: false);

            FunctionResult result = await this.executor.TryExecuteAsync(triggerInput, CancellationToken.None);

            if (!result.Succeeded)
            {
                // Flow the original activity function exception to the orchestration
                // without the outer FunctionInvocationException.
                Exception exceptionToReport = StripFunctionInvocationException(result.Exception);

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

                if (exceptionToReport != null)
                {
                    throw new TaskFailureException(
                              $"Activity function '{this.activityName}' failed: {exceptionToReport.Message}",
                              Utils.SerializeCause(exceptionToReport, MessagePayloadDataConverter.Default));
                }
            }

            string serializedOutput = inputContext.GetSerializedOutput();

            this.config.TraceHelper.FunctionCompleted(
                this.config.HubName,
                this.activityName,
                this.activityVersion,
                instanceId,
                this.config.GetIntputOutputTrace(serializedOutput),
                continuedAsNew: false,
                functionType: FunctionType.Activity,
                isReplay: false);

            return(serializedOutput);
        }
Beispiel #3
0
            public Task <ITriggerData> BindAsync(object value, ValueBindingContext context)
            {
                // If we are not directly passed a DurableActivityContext, we can assume we are being called directly
                // by the admin API. This is mainly used for the Azure Portal execution scenario.
                if (!(value is DurableActivityContext activityContext))
                {
                    if (!(value is string serializedInput))
                    {
                        throw new InvalidOperationException($"Cannot execute an Activity Trigger without a {nameof(DurableActivityContext)} or a {nameof(String)} that represents the serialized input.");
                    }

                    // Durable functions expects input as a JArray with one element.
                    serializedInput = $"[{serializedInput}]";

                    activityContext = new DurableActivityContext(this.durableTaskConfig, Guid.NewGuid().ToString(), serializedInput);
                }

                Type destinationType = this.parameterInfo.ParameterType;

                object convertedValue;

                if (destinationType == typeof(object))
                {
                    convertedValue = value;
                }
                else if (destinationType == typeof(IDurableActivityContext))
                {
                    convertedValue = activityContext;
                }
                else if (destinationType == typeof(JObject))
                {
                    convertedValue = ActivityContextToJObject(activityContext);
                }
                else
                {
                    convertedValue = activityContext.GetInput(destinationType);
                }

                var inputValueProvider = new ObjectValueProvider(
                    convertedValue,
                    this.parameterInfo.ParameterType);

                // Note that there could be conflicts in thiese dictionary keys, in which case
                // the order here determines which binding rule will win.
                var bindingData = new Dictionary <string, object>(StringComparer.OrdinalIgnoreCase);

                bindingData[InstanceIdBindingPropertyName] = ((IDurableActivityContext)activityContext).InstanceId;
                bindingData[this.parameterInfo.Name]       = convertedValue;
                bindingData[DataBindingPropertyName]       = activityContext.GetInputAsJson();

                var triggerData = new TriggerData(inputValueProvider, bindingData);

                triggerData.ReturnValueProvider = new ActivityTriggerReturnValueBinder(
                    activityContext,
                    this.parameterInfo.ParameterType);

                return(Task.FromResult <ITriggerData>(triggerData));
            }
Beispiel #4
0
        public override async Task <string> RunAsync(TaskContext context, string rawInput)
        {
            string instanceId   = context.OrchestrationInstance.InstanceId;
            var    inputContext = new DurableActivityContext(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.HubName,
                this.activityName,
                this.activityVersion,
                instanceId,
                this.config.GetIntputOutputTrace(rawInput),
                isOrchestrator: false,
                isReplay: false);

            FunctionResult result = await this.executor.TryExecuteAsync(triggerInput, CancellationToken.None);

            if (!result.Succeeded)
            {
                this.config.TraceHelper.FunctionFailed(
                    this.config.HubName,
                    this.activityName,
                    this.activityVersion,
                    instanceId,
                    result.Exception?.ToString() ?? string.Empty,
                    isOrchestrator: false,
                    isReplay: false);

                if (result.Exception != null)
                {
                    // Preserve the original exception context so that the durable task
                    // framework can report useful failure information.
                    ExceptionDispatchInfo.Capture(result.Exception).Throw();
                }
            }

            string serializedOutput = inputContext.GetSerializedOutput();

            this.config.TraceHelper.FunctionCompleted(
                config.HubName,
                this.activityName,
                this.activityVersion,
                instanceId,
                this.config.GetIntputOutputTrace(serializedOutput),
                continuedAsNew: false,
                isOrchestrator: false,
                isReplay: false);

            return(serializedOutput);
        }
Beispiel #5
0
            private static JObject ActivityContextToJObject(DurableActivityContext arg)
            {
                JToken token = arg.GetInputAsJson();

                if (token == null)
                {
                    return(null);
                }

                JObject jObj = token as JObject;

                if (jObj == null)
                {
                    throw new ArgumentException($"Cannot convert '{token}' to a JSON object.");
                }

                return(jObj);
            }
        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}.");
            }
        }
Beispiel #7
0
 public ActivityTriggerReturnValueBinder(DurableActivityContext context, Type valueType)
 {
     this.context   = context ?? throw new ArgumentNullException(nameof(context));
     this.valueType = valueType ?? throw new ArgumentNullException(nameof(valueType));
 }
Beispiel #8
0
        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);

            FunctionResult result;

            try
            {
                result = await this.executor.TryExecuteAsync(triggerInput, CancellationToken.None);
            }
            catch (Exception e)
            {
                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: {e}",
                    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}'.", e);
            }

            if (!result.Succeeded)
            {
                // Flow the original activity function exception to the orchestration
                // without the outer FunctionInvocationException.
                Exception exceptionToReport = StripFunctionInvocationException(result.Exception);

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

                if (exceptionToReport != null)
                {
                    throw new TaskFailureException(
                              $"Activity function '{this.activityName}' failed: {exceptionToReport.Message}",
                              Utils.SerializeCause(exceptionToReport, this.config.DataConverter.ErrorConverter));
                }
            }

            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);

            return(serializedOutput);
        }
 private static string ActivityContextToString(DurableActivityContext arg)
 {
     return(arg.GetInput <string>());
 }
 private static JObject ActivityContextToJObject(DurableActivityContext arg)
 {
     return(JObject.Parse(arg.GetRawInput()));
 }