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