Exemple #1
0
        public T GetResult <T>(MessagePayloadDataConverter messageDataConverter, MessagePayloadDataConverter errorDataConverter)
        {
            if (this.IsException)
            {
                Exception e = null;

                // do a best-effort attempt at deserializing this exception
                try
                {
                    var type = Type.GetType(this.ExceptionType, true);
                    e = (Exception)errorDataConverter.Deserialize(this.Result, type);
                }
                catch
                {
                }

                if (e == null)
                {
                    // Could not deserialize. Let's just wrap it legibly,
                    // to help developers figure out what happened
                    e = new FunctionFailedException($"Entity operation threw {this.ExceptionType}, content = {this.Result}");
                }

                throw e;
            }
            else if (this.Result == null)
            {
                return(default(T));
            }
            else
            {
                return(messageDataConverter.Deserialize <T>(this.Result));
            }
        }
Exemple #2
0
 public DurableEntityContext(DurableTaskExtension config, EntityId entity, TaskEntityShim shim)
     : base(config, entity.EntityName)
 {
     this.dataConverter = config.DataConverter;
     this.self          = entity;
     this.shim          = shim;
 }
 public TaskOrchestrationShim(DurableTaskExtension config, DurabilityProvider durabilityProvider, string name)
     : base(config)
 {
     this.dataConverter = config.DataConverter;
     this.context       = new DurableOrchestrationContext(config, durabilityProvider, name);
     this.outOfProcShim = new OutOfProcOrchestrationShim(this.context);
 }
Exemple #4
0
 internal DurableOrchestrationContext(DurableTaskExtension config, DurabilityProvider durabilityProvider, string functionName)
     : base(config, functionName)
 {
     this.dataConverter      = config.DataConverter;
     this.durabilityProvider = durabilityProvider;
     this.actionCount        = 0;
     this.maxActionCount     = config.Options.MaxOrchestrationActions;
 }
Exemple #5
0
 public TaskEntityShim(DurableTaskExtension config, string schedulerId)
     : base(config)
 {
     this.dataConverter = config.DataConverter;
     this.SchedulerId   = schedulerId;
     this.EntityId      = EntityId.GetEntityIdFromSchedulerId(schedulerId);
     this.context       = new DurableEntityContext(config, this.EntityId, this);
 }
Exemple #6
0
 public DurableEntityContext(DurableTaskExtension config, DurabilityProvider durabilityProvider, EntityId entity, TaskEntityShim shim)
     : base(config, entity.EntityName)
 {
     this.messageDataConverter = config.MessageDataConverter;
     this.errorDataConverter   = config.ErrorDataConverter;
     this.durabilityProvider   = durabilityProvider;
     this.self = entity;
     this.shim = shim;
 }
 public TaskEntityShim(DurableTaskExtension config, DurabilityProvider durabilityProvider, string schedulerId)
     : base(config)
 {
     this.messageDataConverter = config.MessageDataConverter;
     this.errorDataConverter   = config.ErrorDataConverter;
     this.SchedulerId          = schedulerId;
     this.EntityId             = EntityId.GetEntityIdFromSchedulerId(schedulerId);
     this.context = new DurableEntityContext(config, durabilityProvider, this.EntityId, this);
 }
        public HttpApiHandler(DurableTaskExtension config, ILogger logger)
        {
            this.config = config;
            this.messageDataConverter = this.config.MessageDataConverter;
            this.logger = logger;

            // The listen URL must not include the path.
            this.localHttpListener = new LocalHttpListener(
                config,
                this.HandleRequestAsync);
        }
 public T GetInput <T>(MessagePayloadDataConverter dataConverter)
 {
     try
     {
         return(dataConverter.MessageConverter.Deserialize <T>(this.Input));
     }
     catch (Exception e)
     {
         throw new EntitySchedulerException($"Failed to deserialize input for operation '{this.Operation}': {e.Message}", e);
     }
 }
 public object GetInput(Type inputType, MessagePayloadDataConverter dataConverter)
 {
     try
     {
         return(dataConverter.Deserialize(this.Input, inputType));
     }
     catch (Exception e)
     {
         throw new EntitySchedulerException($"Failed to deserialize input for operation '{this.Operation}': {e.Message}", e);
     }
 }
Exemple #11
0
 public void SetResult(object result, MessagePayloadDataConverter dataConverter)
 {
     this.ExceptionType = null;
     if (result is JToken jtoken)
     {
         this.Result = jtoken.ToString(Formatting.None);
     }
     else
     {
         this.Result = dataConverter.Serialize(result);
     }
 }
        private async Task <HttpResponseMessage> HandlePostEntityOperationRequestAsync(
            HttpRequestMessage request,
            EntityId entityId)
        {
            IDurableEntityClient client = this.GetClient(request);

            string operationName;

            if (request.Method == HttpMethod.Delete)
            {
                operationName = "delete";
            }
            else
            {
                operationName = request.GetQueryNameValuePairs()["op"] ?? string.Empty;
            }

            if (request.Content == null || request.Content.Headers.ContentLength == 0)
            {
                await client.SignalEntityAsync(entityId, operationName);

                return(request.CreateResponse(HttpStatusCode.Accepted));
            }
            else
            {
                string requestContent = await request.Content.ReadAsStringAsync();

                string mediaType = request.Content.Headers.ContentType?.MediaType;
                object operationInput;
                if (string.Equals(mediaType, "application/json", StringComparison.OrdinalIgnoreCase))
                {
                    try
                    {
                        operationInput = MessagePayloadDataConverter.ConvertToJToken(requestContent);
                    }
                    catch (JsonException e)
                    {
                        return(request.CreateErrorResponse(HttpStatusCode.BadRequest, "Could not parse JSON content: " + e.Message));
                    }
                }
                else
                {
                    operationInput = requestContent;
                }

                await client.SignalEntityAsync(entityId, operationName, operationInput);

                return(request.CreateResponse(HttpStatusCode.Accepted));
            }
        }
        public HttpApiHandler(DurableTaskExtension config, ILogger logger)
        {
            this.config = config;
            this.messageDataConverter = this.config.MessageDataConverter;
            this.logger = logger;

            // The listen URL must not include the path.
            var listenUri = new Uri(InternalRpcUri.GetLeftPart(UriPartial.Authority));

            this.localHttpListener = new LocalHttpListener(
                config,
                listenUri,
                this.HandleRequestAsync);
        }
Exemple #14
0
        /// <summary>
        /// Gets the input of the current activity function instance as a <c>JToken</c>.
        /// </summary>
        /// <returns>
        /// The parsed <c>JToken</c> representation of the activity input.
        /// </returns>
        internal JToken GetInputAsJson()
        {
            if (this.serializedInput != null && this.parsedJsonInput == null)
            {
                var objectArray = this.messageDataConverter.Deserialize <object[]>(this.serializedInput);

                if (objectArray?.Length != 1)
                {
                    throw new ArgumentException("The serialized input is expected to be an object array with one element.");
                }

                this.parsedJsonInput = MessagePayloadDataConverter.ConvertToJToken(this.messageDataConverter.Serialize(objectArray[0]));
            }

            return(this.parsedJsonInput);
        }
        private async Task <HttpResponseMessage> HandleRaiseEventRequestAsync(
            HttpRequestMessage request,
            string instanceId,
            string eventName)
        {
            IDurableOrchestrationClient client = this.GetClient(request);

            DurableOrchestrationStatus status = await client.GetStatusAsync(instanceId);

            if (status == null)
            {
                return(request.CreateResponse(HttpStatusCode.NotFound));
            }

            switch (status.RuntimeStatus)
            {
            case OrchestrationRuntimeStatus.Failed:
            case OrchestrationRuntimeStatus.Canceled:
            case OrchestrationRuntimeStatus.Terminated:
            case OrchestrationRuntimeStatus.Completed:
                return(request.CreateResponse(HttpStatusCode.Gone));
            }

            string mediaType = request.Content.Headers.ContentType?.MediaType;

            if (!string.Equals(mediaType, "application/json", StringComparison.OrdinalIgnoreCase))
            {
                return(request.CreateErrorResponse(HttpStatusCode.BadRequest, "Only application/json request content is supported"));
            }

            string stringData = await request.Content.ReadAsStringAsync();

            object eventData;

            try
            {
                eventData = MessagePayloadDataConverter.ConvertToJToken(stringData);
            }
            catch (JsonReaderException e)
            {
                return(request.CreateErrorResponse(HttpStatusCode.BadRequest, "Invalid JSON content", e));
            }

            await client.RaiseEventAsync(instanceId, eventName, eventData);

            return(request.CreateResponse(HttpStatusCode.Accepted));
        }
        internal DurableClient(
            DurabilityProvider serviceClient,
            DurableTaskExtension config,
            HttpApiHandler httpHandler,
            DurableClientAttribute attribute)
        {
            this.config = config ?? throw new ArgumentNullException(nameof(config));

            this.dataConverter = config.DataConverter;

            this.client             = new TaskHubClient(serviceClient, this.dataConverter);
            this.durabilityProvider = serviceClient;
            this.traceHelper        = config.TraceHelper;
            this.httpApiHandler     = httpHandler;
            this.hubName            = attribute.TaskHub ?? config.Options.HubName;
            this.attribute          = attribute;
        }
 public void SetInput(object obj, MessagePayloadDataConverter dataConverter)
 {
     try
     {
         if (obj is JToken jtoken)
         {
             this.Input = jtoken.ToString(Formatting.None);
         }
         else
         {
             this.Input = dataConverter.Serialize(obj);
         }
     }
     catch (Exception e)
     {
         throw new EntitySchedulerException($"Failed to serialize input for operation '{this.Operation}': {e.Message}", e);
     }
 }
        internal DurableClient(
            DurabilityProvider serviceClient,
            HttpApiHandler httpHandler,
            DurableClientAttribute attribute,
            MessagePayloadDataConverter messageDataConverter,
            EndToEndTraceHelper traceHelper,
            DurableTaskOptions durableTaskOptions)
        {
            this.messageDataConverter = messageDataConverter;

            this.client             = new TaskHubClient(serviceClient, this.messageDataConverter);
            this.durabilityProvider = serviceClient;
            this.traceHelper        = traceHelper;
            this.httpApiHandler     = httpHandler;
            this.durableTaskOptions = durableTaskOptions;
            this.hubName            = attribute.TaskHub ?? this.durableTaskOptions.HubName;
            this.attribute          = attribute;
        }
        private void InitializeForFunctionsV1(ExtensionConfigContext context)
        {
#if FUNCTIONS_V1
            context.ApplyConfig(this.Options, "DurableTask");
            this.nameResolver = context.Config.NameResolver;
            this.ResolveAppSettingOptions();
            ILogger logger = context.Config.LoggerFactory.CreateLogger(LoggerCategoryName);
            this.TraceHelper = new EndToEndTraceHelper(logger, this.Options.Tracing.TraceReplayEvents);
            this.connectionStringResolver    = new WebJobsConnectionStringProvider();
            this.durabilityProviderFactory   = new AzureStorageDurabilityProviderFactory(new OptionsWrapper <DurableTaskOptions>(this.Options), this.connectionStringResolver);
            this.defaultDurabilityProvider   = this.durabilityProviderFactory.GetDurabilityProvider();
            this.LifeCycleNotificationHelper = this.CreateLifeCycleNotificationHelper();
            var messageSerializerSettingsFactory = new MessageSerializerSettingsFactory();
            var errorSerializerSettingsFactory   = new ErrorSerializerSettingsFactory();
            this.MessageDataConverter = new MessagePayloadDataConverter(messageSerializerSettingsFactory.CreateJsonSerializerSettings(), true);
            this.ErrorDataConverter   = new MessagePayloadDataConverter(errorSerializerSettingsFactory.CreateJsonSerializerSettings(), true);
            this.HttpApiHandler       = new HttpApiHandler(this, logger);
#endif
        }
Exemple #20
0
        public void SetExceptionResult(Exception exception, string operation, MessagePayloadDataConverter errorDataConverter)
        {
            this.ExceptionType = exception.GetType().AssemblyQualifiedName;

            try
            {
                this.Result = errorDataConverter.Serialize(exception);
            }
            catch (Exception)
            {
                // sometimes, exceptions cannot be serialized. In that case we create a serializable wrapper
                // exception which lets the caller know something went wrong.

                var wrapper = string.IsNullOrEmpty(operation) ?
                              new OperationErrorException($"{this.ExceptionType} while processing operations: {exception.Message}")
                    : new OperationErrorException($"{this.ExceptionType} in operation '{operation}': {exception.Message}");

                this.ExceptionType = wrapper.GetType().AssemblyQualifiedName;
                this.Result        = errorDataConverter.Serialize(wrapper);
            }
        }
        internal static JToken ParseToJToken(string value)
        {
            if (value == null)
            {
                return(NullJValue);
            }

            // Ignore whitespace
            value = value.Trim();
            if (value.Length == 0)
            {
                return(string.Empty);
            }

            try
            {
                return(MessagePayloadDataConverter.ConvertToJToken(value));
            }
            catch (JsonReaderException)
            {
                // Return the raw string value as the fallback. This is common in terminate scenarios.
                return(value);
            }
        }
Exemple #22
0
 public HttpApiHandler(DurableTaskExtension config, ILogger logger)
 {
     this.config        = config;
     this.dataConverter = this.config.DataConverter;
     this.logger        = logger;
 }
 internal DurableActivityContext(DurableTaskExtension config, string instanceId, string serializedInput)
 {
     this.dataConverter   = config.DataConverter;
     this.instanceId      = instanceId;
     this.serializedInput = serializedInput;
 }
        private static async Task <DurableOrchestrationStatus> GetDurableOrchestrationStatusAsync(OrchestrationState orchestrationState, TaskHubClient client, bool showHistory, bool showHistoryOutput)
        {
            JArray historyArray = null;

            if (showHistory && orchestrationState.OrchestrationStatus != OrchestrationStatus.Pending)
            {
                string history = await client.GetOrchestrationHistoryAsync(orchestrationState.OrchestrationInstance);

                if (!string.IsNullOrEmpty(history))
                {
                    historyArray = MessagePayloadDataConverter.ConvertToJArray(history);

                    var eventMapper = new Dictionary <string, EventIndexDateMapping>();
                    var indexList   = new List <int>();

                    for (var i = 0; i < historyArray.Count; i++)
                    {
                        JObject historyItem = (JObject)historyArray[i];
                        if (Enum.TryParse(historyItem["EventType"].Value <string>(), out EventType eventType))
                        {
                            // Changing the value of EventType from integer to string for better understanding in the history output
                            historyItem["EventType"] = eventType.ToString();
                            switch (eventType)
                            {
                            case EventType.TaskScheduled:
                                TrackNameAndScheduledTime(historyItem, eventType, i, eventMapper);
                                historyItem.Remove("Version");
                                historyItem.Remove("Input");
                                break;

                            case EventType.TaskCompleted:
                            case EventType.TaskFailed:
                                AddScheduledEventDataAndAggregate(ref eventMapper, "TaskScheduled", historyItem, indexList);
                                historyItem["TaskScheduledId"]?.Parent.Remove();
                                if (!showHistoryOutput && eventType == EventType.TaskCompleted)
                                {
                                    historyItem.Remove("Result");
                                }

                                ConvertOutputToJToken(historyItem, showHistoryOutput && eventType == EventType.TaskCompleted);
                                break;

                            case EventType.SubOrchestrationInstanceCreated:
                                TrackNameAndScheduledTime(historyItem, eventType, i, eventMapper);
                                historyItem.Remove("Version");
                                historyItem.Remove("Input");
                                break;

                            case EventType.SubOrchestrationInstanceCompleted:
                            case EventType.SubOrchestrationInstanceFailed:
                                AddScheduledEventDataAndAggregate(ref eventMapper, "SubOrchestrationInstanceCreated", historyItem, indexList);
                                historyItem.Remove("TaskScheduledId");
                                if (!showHistoryOutput && eventType == EventType.SubOrchestrationInstanceCompleted)
                                {
                                    historyItem.Remove("Result");
                                }

                                ConvertOutputToJToken(historyItem, showHistoryOutput && eventType == EventType.SubOrchestrationInstanceCompleted);
                                break;

                            case EventType.ExecutionStarted:
                                var functionName = historyItem["Name"];
                                historyItem.Remove("Name");
                                historyItem["FunctionName"] = functionName;
                                historyItem.Remove("OrchestrationInstance");
                                historyItem.Remove("ParentInstance");
                                historyItem.Remove("Version");
                                historyItem.Remove("Tags");
                                historyItem.Remove("Input");
                                break;

                            case EventType.ExecutionCompleted:
                                if (Enum.TryParse(historyItem["OrchestrationStatus"].Value <string>(), out OrchestrationStatus orchestrationStatus))
                                {
                                    historyItem["OrchestrationStatus"] = orchestrationStatus.ToString();
                                }

                                if (!showHistoryOutput)
                                {
                                    historyItem.Remove("Result");
                                }

                                ConvertOutputToJToken(historyItem, showHistoryOutput);
                                break;

                            case EventType.ExecutionTerminated:
                                historyItem.Remove("Input");
                                break;

                            case EventType.TimerFired:
                                historyItem.Remove("TimerId");
                                break;

                            case EventType.EventRaised:
                                historyItem.Remove("Input");
                                break;

                            case EventType.OrchestratorStarted:
                            case EventType.OrchestratorCompleted:
                                indexList.Add(i);
                                break;
                            }

                            historyItem.Remove("EventId");
                            historyItem.Remove("IsPlayed");
                        }
                    }

                    var counter = 0;
                    indexList.Sort();
                    foreach (var indexValue in indexList)
                    {
                        historyArray.RemoveAt(indexValue - counter);
                        counter++;
                    }
                }
            }

            return(ConvertOrchestrationStateToStatus(orchestrationState, historyArray));
        }